使用基类和基本模块重构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调用东西,但你不能从模块中做到这一点。
这取决于你真正想做的事情。
- 覆盖或添加ActiveRecord :: Base的方法 :如果您希望应用程序中的每个ActiveRecord模型都
respond_to
foo
,请执行此操作。 - 子类ActiveRecord :: Base,并且每个模型都inheritance自您的子类 :实现与1相同,但是应用程序中的每个模型都需要扩展非常规类,所以为什么要经历麻烦。
- 包含模块 :如果只有少数模型需要访问
foo
这种方法很有用。 这几乎就是所有那些acts_as_
插件所做的事情。
最重要的是,如果您希望每个模型都具有与ActiveRecord :: Base已提供的不同的行为,请使用选项1.如果只有少数模型需要该行为,请创建一个模块并将其包含在模型中(选项3) )。