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
比其他方式更优惠吗?
答案 0 :(得分:24)
这两种方法之间存在根本区别,所有其他答案都缺失了,而且是rails的STI实现(单表继承):
http://api.rubyonrails.org/classes/ActiveRecord/Base.html(查找“单表继承”部分)
基本上,如果您像这样重构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”。如果它们具有相同的属性,则必须在两个表中重复列,但如果存在差异,则不会对它们进行反复化。
所以,如果一个优于另一个,是的,但这是特定于您的应用程序。根据经验,如果它们具有完全相同的属性或大的重叠,则使用STI(第一个示例),否则,使用模块(第二个示例)。
答案 1 :(得分:5)
这两种方法都有效。在决定使用模块或类时,我遇到的问题是类是否适合对象层次结构,或者这些只是我希望重用的方法。如果我只是试图将干扰原因的公共代码分解出来,那听起来像是一个模块。如果真的有一个类适合于自己有意义的层次结构,我会使用一个类。
来自Java背景,我可以选择做出这些决定。
答案 2 :(得分:4)
您可以更灵活地使用该模块。该模块的目的是跨越不同类型的类。使用另一种方法,您可以将自己锁定在Base中。除此之外,没有太大区别。
Ruby对多重继承的回答是mixins。由于您的类已经从Rails特定类继承,因此它们不能再继承自定义类。
所以你的选择是在长链中连在一起,或者使用更干净,更容易理解的mixin。
答案 3 :(得分:1)
该模块为您提供了更大的灵活性1)您只能从一个类继承,但您可以包含多个模块,以及2)您不能继承基类而不继承其超类,但您可以包含模块本身(例如,您可能希望将“foo”方法添加到另一个不是活动记录模型的类中。)
另一个区别是,在Base类的方法中你可以从ActiveRecord :: Base调用东西,但你不能从模块中做到这一点。
答案 4 :(得分:1)
这取决于你真正想做的事情。
respond_to
foo
,请执行此操作。foo
,这项功能非常有用。这几乎就是所有acts_as_<whatever>
个插件所做的。最重要的是,如果您希望每个模型都具有与ActiveRecord :: Base已提供的不同的行为,请使用选项1.如果只有少数模型需要该行为,请创建模块并将其包含在模型中(备选方案3)。