#ruby-on-rails-3 #polymorphism #sti
#ruby-on-rails-3 #полиморфизм #sti
Вопрос:
Я работаю над проектом (Rails 3.0.3), где, я думаю, мне может понадобиться использовать STI, но я не уверен, должен ли я просто добавить дополнительный столбец в таблицу и покончить с этим.
В моей объектной модели (для игровой системы) У меня есть игроки (которые принадлежат агентствам) и владельцы (которые владеют агентствами).
И игроки, и владельцы принадлежат агентам, которые являются учетной записью пользователя, поэтому агент может быть игроком и / или владельцем во многих агентствах.
Я должен был назвать агента ‘user’ вместо этого, упс. Итак, у меня есть это:
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
Игрок и владелец имеют абсолютно одинаковые атрибуты, единственное различие между ними заключается в том, что у владельца другие отношения с агентством, чем у Игрока (владелец владеет агентством, у Агентства только один владелец, но много игроков).
Кроме того, Владельцу предоставляются особые права, такие как возможность изменять настройки в агентстве.
С точки зрения чистой ООП, Owner является подклассом Player (или, Owner и Player оба являются подклассами какого-то неопределенного класса, такого как Participant или что-то в этом роде), но при учете постоянства кажется, что дизайн базы данных с отдельными таблицами players и owners является плохим.
Моей первой мыслью было провести рефакторинг и использовать STI и либо сделать Owner подклассом Player, либо ввести новый базовый класс, а затем подклассы Owner и Player.
Моя другая мысль заключалась в том, что я мог бы просто добавить столбец boolean / tinyint в Player с именем is_owner, но я могу предвидеть, что это потенциально приведет к некоторому неприятному представлению и коду контроллера.
Мне было интересно, сталкивался ли кто-нибудь с подобными обстоятельствами и, возможно, имеет какой-либо совет или мог бы указать мне на какие-нибудь хорошие онлайн-ресурсы, чтобы прочитать о STI?
Комментарии:
1. Ps. Я не думаю, что вам нужно
:class_name => and :foreign_key =>
для кода в классахPlayer
иOwner
.2. Ах да, вы правы. Они были оставлены по умолчанию Textmate. Спасибо, что указали на это.
Ответ №1:
Возможно, вам следует думать о Player
и Owner
как об отношениях между Agent
и Agency
. Итак, Agent
владеет Agency
и Agent
играет в игры с an Agency
. Следовательно, вы могли бы ввести концепцию роли и, следовательно, модели, Role
от которой Player
наследуются и Owner
. Вопрос в том, хотели ли вы когда-нибудь использовать Role
модель? Или ваше приложение предназначено для владельцев и игроков, и за исключением некоторых общих атрибутов, это две совершенно разные вещи?
Если это две разные вещи, то вы должны создать для них две разные модели. Если у вас есть некоторое дублирование кода между двумя моделями, то вы можете использовать (или несколько) микшин (ов) для совместного использования кода между ними.
В общем, я предпочитаю композицию наследованию. Во-первых, наследование выглядит как элегантный способ совместного использования кода между классами, но дело не в этом. Наследование касается типов и интерфейсов. Следовательно, вы объединяете вещи с точки зрения их интерфейсов. Это сильное ограничение при дальнейшей разработке ваших моделей.
Я использую наследование, только если существует реальная is_a
связь, а не shares_some_code_with
отношение между классами to. И что более важно: я использую его тогда и только тогда, когда у него есть техническое преимущество для меня. В противном случае есть гораздо лучшие способы совместного использования кода между классами в ruby.