Rails 3:我应该使用STI还是只使用额外的列? (寻求建议)

时间:2011-05-30 18:15:22

标签: ruby-on-rails-3 polymorphism sti

我正在开发一个项目(Rails 3.0.3),我认为我可能需要使用STI,但我不确定是否应该在表中添加一个额外的列并完成它。

在我的对象模型中,(对于游戏系统)我有玩家(属于代理商)和所有者(拥有代理商)。

玩家和所有者都由代理商拥有,代理商是一个用户帐户,因此代理商可以是许多代理商的玩家和/或所有者。

我应该命名代理'用户',而不是oops。所以我有这个:

class Agency < ActiveRecord::Base
  has_many :players, :class_name => "Player", :foreign_key => "agency_id"
  has_many :agents, :through => :players, :source => :agent_id
  has_one :owner, :class_name => "Owner", :foreign_key => "agency_id"
end

class Player < ActiveRecord::Base
  belongs_to :agency, :class_name => "Agency", :foreign_key => "agency_id"
  belongs_to :agent, :class_name => "Agent", :foreign_key => "agent_id"
end

class Owner < ActiveRecord::Base
  belongs_to :agency, :class_name => "Agency", :foreign_key => "agency_id"
  belongs_to :agent, :class_name => "Agent", :foreign_key => "agent_id"
end

玩家和所有者都拥有完全相同的属性,两者之间的唯一区别是所有者与代理商的关系与玩家不同(所有者拥有代理商,代理商只有一个所有者,但拥有许多玩家)

此外,所有者还享有特殊权利,例如调整代理商设置的能力。

从纯OOP的角度来看,所有者是Player的子类(或者,所有者和玩家都是某些未定义类的子类,如参与者或其他东西),但是当考虑持久性时,似乎糟糕的数据库设计需要单独的玩家和业主表。

我的第一个想法是重构和使用STI,要么将Owner作为Player的子类,要么引入一个新的基类,然后将Owner和Player子类化。

我的另一个想法是,我可以在播放器中添加一个名为is_owner的boolean / tinyint列,但我可以预见到这可能导致一些讨厌的视图和控制器代码。

我想知道是否有人遇到类似的情况,可能有任何建议或者可以指点一些好的在线资源来阅读STI?

1 个答案:

答案 0 :(得分:1)

也许您应该将PlayerOwner视为AgentAgency之间的关系。因此,Agent 拥有 AgencyAgent Agency的游戏。因此,您可以引入角色的概念,从而引入RolePlayer继承的模型Owner。问题是:您是否想要使用Role模型?或者你的应用是关于业主和球员,除了一些常见的属性,他们是两种完全不同的东西?

如果它们是两个不同的东西,那么你应该让它们成为两个不同的模型。如果两个模型之间存在一些代码重复,那么您可以使用(或多个)mixin(s)在它们之间共享代码。

一般来说,我更喜欢构图而不是继承。首先,继承看起来像是一种在类之间共享代码的优雅方式,但它不是那样的。继承是关于类型和接口。因此,您可以根据接口进行耦合。这是模型进一步发展的强大约束。

仅当存在真正的is_a关系而不是类之间的shares_some_code_with关系时才使用继承。更重要的是:当且仅当它对我有技术优势时才使用它。否则,有更好的方法在ruby中的类之间共享代码。