Рефакторинг моделей ActiveRecord с базовым классом по сравнению с базовым модулем
Класс A и B идентичны:
class A < ActiveRecord::Base
def foo
puts "foo"
end
end
class B < ActiveRecord::Base
def foo
puts "foo"
end
end
Какая разница между рефакторингом, подобным этому, с базовым классом:
class Base < ActiveRecord::Base
def foo
puts "foo"
end
end
class A < Base
end
class B < Base
end
в отличие от этого, используя базовый модуль :
module Base
def foo
puts "foo"
end
end
class A < ActiveRecord::Base
include Base
end
class B < ActiveRecord::Base
include Base
end
Один предпочтительный вариант для другого?
Ответы
Ответ 1
Существует принципиальное различие между этими двумя методами, которые отсутствуют во всех остальных ответах, и что реализация рельсов ИППП (однонамерное наследование):
http://api.rubyonrails.org/classes/ActiveRecord/Base.html (найдите раздел "Наследование отдельных таблиц" )
В принципе, если вы реорганизуете свой базовый класс следующим образом:
class Base < ActiveRecord::Base
def foo
puts "foo"
end
end
class A < Base
end
class B < Base
end
Затем вы должны иметь таблицу базы данных, называемую "base", с столбцом "type", который должен иметь значение "A" или "B". Столбцы этой таблицы будут одинаковыми для всех ваших моделей, и если у вас есть столбец, принадлежащий только одной из моделей, ваша таблица "оснований" будет денормализирована.
Если вы реорганизуете свой базовый класс следующим образом:
Module Base
def foo
puts "foo"
end
end
class A < ActiveRecord::Base
include Base
end
class B < ActiveRecord::Base
include Base
end
Тогда не будет табличных "баз". Вместо этого будет таблица "как" и таблица "bs". Если они имеют одинаковые атрибуты, столбцы должны быть дублированы в обеих таблицах, но если есть различия, они не будут деномализированы.
Итак, если предпочтительнее другого, да, но это специфично для вашего приложения. Как правило, если у них есть те же самые свойства или большое перекрытие, используйте STI (1-й пример), иначе используйте модули (2-й пример).
Ответ 2
Оба эти метода будут работать. Когда вы решаете использовать модуль или класс, вопрос, который у меня есть, заключается в том, что класс вписывается в иерархию объектов, или это просто методы, которые я ищу для повторного использования. Если я просто пытаюсь разложить общий код по причинам DRY, это звучит как модуль. Если действительно существует класс, который вписывается в иерархию, которая имеет смысл сама по себе, я использую класс.
Исходя из фона Java, он обновляется, и я могу решить эти решения.
Ответ 3
У вас больше гибкости с модулем. Цель модуля - охватывать разные типы классов. С помощью другого метода вы запираетесь на Base. Кроме этого, нет большой разницы.
Ответ Ruby на множественное наследование - mixins. Поскольку ваши классы уже наследуются от определенных классов Rails, они больше не могут наследовать ваши пользовательские классы.
Таким образом, ваш выбор состоит в том, чтобы объединиться в длинной цепочке или использовать миксин, который намного чище и легче понять.
Ответ 4
Модуль дает вам больше гибкости в том, что 1) вы можете наследовать только один класс, но можете включать несколько модулей, и 2) вы не можете наследовать из базового класса, не наследуя его суперклассы, но вы можете включить (например, вы можете добавить метод "foo" к другому классу, который не является активной моделью записи).
Другое отличие состоит в том, что в методах в классе Base вы можете вызывать вещи из ActiveRecord:: Base, но вы не могли сделать этого из модуля.
Ответ 5
Это зависит от того, что вы действительно пытаетесь сделать.
- Переопределение или добавление методов в ActiveRecord:: Base: сделайте это, если вы хотите, чтобы каждая модель ActiveRecord в вашем приложении была
respond_to
foo
.
- Подкласс ActiveRecord:: Base и каждая модель наследуется от вашего подкласса: Достигает того же, что и 1, но каждая модель в вашем приложении должна распространять нетрадиционный класс, поэтому зачем беспокоиться.
- include module: Это отлично работает, если только некоторое количество моделей нуждается в доступе к
foo
. Это в значительной степени то, что делают все эти плагины acts_as_<whatever>
.
В нижней строке, если вы хотите, чтобы каждая модель имела другое поведение по сравнению с тем, что уже предлагает ActiveRecord:: Base, используйте параметр 1. Если только несколько ваших моделей требуют поведения, создайте модуль и включите его в свои модели. (вариант 3).