【问题标题】:Refactoring ActiveRecord models with a base class versus a base module使用基类与基模块重构 ActiveRecord 模型
【发布时间】:2010-12-15 02:53:39
【问题描述】:

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

一种方式比另一种更可取吗?

【问题讨论】:

  • 您的意思是在基类示例的子类中包含 foo 的定义吗?
  • 不,我没有。谢谢。我删除了它。

标签: ruby-on-rails ruby inheritance activerecord mixins


【解决方案1】:

这两种方法之间存在所有其他答案都缺失的根本区别,那就是 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(第一个示例),否则,使用模块(第二个示例)。

【讨论】:

  • 我在玩这个例子时被抓住了,“模块”应该是“模块”
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    这两种方法都可以。在决定使用模块或类时,我的问题是该类是否适合对象层次结构,或者这些只是我希望重用的方法。如果我只是出于 DRY 的原因试图排除通用代码,那听起来像是一个模块。如果真的有一个类适合自己有意义的层次结构,我会使用一个类。

    来自 Java 背景,令人耳目一新,我可以选择做出这些决定。

    【讨论】:

      【解决方案4】:

      这取决于你真正想要做什么。

      1. 为 ActiveRecord::Base 覆盖或添加方法:如果您希望应用中的每个 ActiveRecord 模型都为respond_tofoo,请执行此操作。
      2. 子类 ActiveRecord::Base,并且每个模型都继承自您的子类:实现与 1 相同,但是您的应用中的每个模型都需要扩展一个非常规的类,所以为什么要这么麻烦。李>
      3. 包含模块:如果只有一些模型需要访问foo,这非常有用。这几乎就是所有acts_as_&lt;whatever&gt; 插件所做的。

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

      【讨论】:

        【解决方案5】:

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

        另一个区别是,在 Base 类的方法中,您可以从 ActiveRecord::Base 调用事物,但不能从模块中调用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-22
          • 2018-08-21
          • 1970-01-01
          • 1970-01-01
          • 2018-12-04
          相关资源
          最近更新 更多