5

我正在开发一个非常大的 Rails 应用程序。我们最初并没有使用太多继承,但我们从顾问那里获得了一些令人大开眼界的经验,并且正在寻求重构我们的一些模型。

我们的应用程序中有很多以下模式:

class Project < ActiveRecord::Base
  has_many :graph_settings
end

class GraphType < ActiveRecord::Base
  has_many :graph_settings
  #graph type specific settings (units, labels, etc) stored in DB and very infrequently updated.
end

class GraphSetting < ActiveRecord::Base
  belongs_to :graph_type
  belongs_to :project
  # Project implementation of graph type specific settings (y_min, y_max) also stored in db.
end

这也导致了视图、助手和 GraphSetting 模型本身中的大量条件。这些都不好。

一个简单的重构,我们摆脱了 GraphType 以支持使用更像这样的结构:

class Graph < ActiveRecord::Base
  belongs_to :project
  # Generic methods and settings
end

class SpecificGraph < Graph
  # Default methods and settings hard coded
  # Project implementation specific details stored in db.
end

现在这对我来说非常有意义,简化了测试,删除了条件,并使以后的国际化更容易。然而,我们只有 15 到 30 个图表。

我们有一个非常相似的模型(以复杂的为例),大约有 100 种不同的“类型”,并且可能会翻倍。它们都有继承的关系和方法,有些需要覆盖比其他方法更多的方法。这似乎是完美的用途,但很多看起来就像很多。

200 个 STI 课程是不是很多?我们应该看看另一种模式吗?

感谢您的智慧,我会回答任何问题。

4

1 回答 1

4

如果差异仅在于班级的行为,那么我认为这应该不是问题,这是 STI 的一个很好的候选者。(请注意,我从来没有尝试过这么多子类。)

但是,如果您的 200 个 STI 类中的每一个都有一些独特的属性,那么您将需要在主表中添加大量额外的数据库列,这些列在 99.5% 的情况下为 NULL。这可能非常低效。

为了创建类似“多表继承”的东西,我之前成功的做法是使用一点元编程来关联其他表以获取每个类独有的细节:

class SpecificGraph < Graph
  include SpecificGraphDetail::MTI
end

class SpecificGraphDetail < ActiveRecord::Base
  module MTI
    def self.included(base)
      base.class_eval do
        has_one :specific_graph_detail, :foreign_key => 'graph_id', :dependent => :destroy
        delegate :extra_column, :extra_column=, :to => :specific_graph_detail
      end
    end
  end
end

委托意味着您可以访问关联的详细信息字段,就好像它们直接在模型上而不是通过specific_graph_detail关联一样,并且出于所有意图和目的,它“看起来”就像这些只是额外的列。

您必须权衡需要加入这些额外详细信息表的情况与仅在主表中拥有额外列的情况。这将决定是使用 STI 还是使用关联表的解决方案,例如我上面的解决方案。

于 2010-09-09T16:07:15.140 回答