使用基类和基本模块重构ActiveRecord模型

A类和B类相同:

class A < ActiveRecord::Base def foo puts "foo" end end class B < ActiveRecord::Base def foo puts "foo" end end 

像这样重构与基类之间有什么区别:

 class Base < ActiveRecord::Base def foo puts "foo" end end class A < Base end class B < Base end 

与使用基本模块的情况相比

 module Base def foo puts "foo" end end class A < ActiveRecord::Base include Base end class B < ActiveRecord::Base include Base end 

有一种方式优于另一种方式吗?

这两种方法之间存在根本区别,缺少所有其他答案,而且是rails的STI实现(单表inheritance):

http://api.rubyonrails.org/classes/ActiveRecord/Base.html (查找“单表inheritance”部分)

基本上,如果你像这样重构你的Base类:

 class Base < ActiveRecord::Base def foo puts "foo" end end class A < Base end class B < Base end 

然后,您应该有一个名为“bases”的数据库表,其中包含一个名为“type”的列,其值应为“A”或“B”。 此表上的列在所有模型中都是相同的,如果您的列只属于其中一个模型,则“基”表将被非规范化。

然而,如果您重构您的Base类,如下所示:

 Module Base def foo puts "foo" end end class A < ActiveRecord::Base include Base end class B < ActiveRecord::Base include Base end 

然后将没有表“基地”。 相反,会有一个表“as”和一个表“bs”。 如果它们具有相同的属性,则必须在两个表中复制列,但如果存在差异,则不会对它们进行denomarlized。

所以,如果一个优于另一个,是的,但这是特定于您的应用程序。 根据经验,如果它们具有完全相同的属性或大的重叠,则使用STI(第一个示例),否则,使用模块(第二个示例)。

这两种方法都有效。 在决定使用模块或类时,我遇到的问题是该类是否适合对象层次结构,或者这些只是我希望重用的方法。 如果我只是想为干扰原因分解公共代码,那听起来就像一个模块。 如果真的有一个类适合自己有意义的层次结构,我会使用一个类。

来自Java背景,我可以选择做出这些决定。

您可以更灵活地使用该模块。 该模块的目的是跨越不同类型的类。 使用另一种方法,您将自己锁定在Base中。 除此之外,没有太大的区别。

Ruby对多重inheritance的回答是mixins。 由于您的类已经从Rails特定类inheritance,因此它们不能再inheritance自定义类。

所以你的选择是在长链中链接在一起,或者使用更干净,更容易理解的mixin。

该模块为您提供了更大的灵活性1)您只能从一个类inheritance,但您可以包含多个模块,以及2)您不能inheritance基类而不inheritance其超类,但您可以包含所有模块本身(例如,您可能希望将“foo”方法添加到另一个不是活动记录模型的类中)。

另一个区别是,在Base类的方法中你可以从ActiveRecord :: Base调用东西,但你不能从模块中做到这一点。

这取决于你真正想做的事情。

  1. 覆盖或添加ActiveRecord :: Base的方法 :如果您希望应用程序中的每个ActiveRecord模型都respond_to foo ,请执行此操作。
  2. 子类ActiveRecord :: Base,并且每个模型都inheritance自您的子类 :实现与1相同,但是应用程序中的每个模型都需要扩展非常规类,所以为什么要经历麻烦。
  3. 包含模块 :如果只有少数模型需要访问foo这种方法很有用。 这几乎就是所有那些acts_as_插件所做的事情。

最重要的是,如果您希望每个模型都具有与ActiveRecord :: Base已提供的不同的行为,请使用选项1.如果只有少数模型需要该行为,请创建一个模块并将其包含在模型中(选项3) )。