Сколько классов слишком много?Рельсы СТИ - PullRequest
5 голосов
/ 09 сентября 2010

Я работаю над очень большим 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 ИППП классов?Есть ли другой шаблон, на который нам следует обратить внимание?

Спасибо за мудрость, и я отвечу на все вопросы.

1 Ответ

4 голосов
/ 09 сентября 2010

Если различия только в поведении класса, то я предполагаю, что это не должно быть проблемой, и это хороший кандидат на ИППП. (Имейте в виду, я никогда не пробовал это с таким количеством подклассов.)

Но если у каждого из 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

Делегирование означает, что вы можете получить доступ к связанным полям сведений, как если бы они были непосредственно в модели, вместо того чтобы проходить через ассоциацию specific_graph_detail, и для всех намерений и целей это "выглядит" так, как будто это просто дополнительные столбцы. *

Вы должны поменять ситуацию, в которой вам нужно объединить эти дополнительные таблицы с подробностями, против наличия дополнительных столбцов в основной таблице. Это решит, использовать ли STI или решение с использованием связанных таблиц, таких как мое решение выше.

...