多少节课太多了?铁路STI

发布于 2024-09-18 14:20:39 字数 1155 浏览 6 评论 0原文

我正在开发一个非常大的 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 节性病课程很多吗?我们还应该关注另一种模式吗?

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

I am working on a very large Rails application. We initially did not use much inheritance, but we have had some eye opening experiences from a consultant and are looking to refactor some of our models.

We have the following pattern a lot in our application:

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

This also results in a ton of conditionals in views, helpers and in the GraphSetting model itself. None of this is good.

A simple refactor where we get rid of GraphType in favor of using a structure more like this:

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

Now this makes perfect sense to me, eases testing, removes conditionals, and makes later internationalization easier. However we only have 15 to 30 graphs.

We have a very similar model (to complicated to use as an example) with close to probably 100 different 'types', and could potentially double that. They would all have relationships and methods they inheritated, some would need to override more methods then others. It seems like the perfect use, but that many just seems like a lot.

Is 200 STI classes to many? Is there another pattern we should look at?

Thanks for any wisdom and I will answer any questions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我的影子我的梦 2024-09-25 14:20:39

如果差异仅在于班级的行为,那么我认为这应该不是问题,并且这是 STI 的良好候选者。 (请注意,我从未尝试过对如此多的子类进行此操作。)

但是,如果您的 200 个 STI 类每个都有一些独特的属性,则您将需要主表中的许多额外数据库列,这些列将为 NULL,其中 99.5%时间。这可能非常低效。

为了创建类似“多表继承”的东西,我之前成功做过的就是使用一些元编程来关联其他表以获取每个类特有的详细信息:

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

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

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

If the differences are just in the behavior of the class, then I assume it shouldn't be a problem, and this is a good candidate for STI. (Mind you, I've never tried this with so many subclasses.)

But, if your 200 STI classes each have some unique attributes, you would need a lot of extra database columns in the master table which would be NULL, 99.5% of the time. This could be very inefficient.

To create something like "multiple table inheritance", what I've done before with success was to use a little metaprogramming to associate other tables for the details unique to each class:

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

The delegation means you can access the associated detail fields as if they were directly on the model instead of going through the specific_graph_detail association, and for all intents and purposes it "looks" like these are just extra columns.

You have to trade off the situations where you need to join these extra detail tables against just having the extra columns in the master table. That will decide whether to use STI or a solution using associated tables, such as my solution above.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文