Когда создавать модуль, а когда использовать наследование?
Сегодня возник вопрос , который заставил меня задуматься о том, насколько разработчики Ruby on Rails действительно понимают инструменты, которые они используют.
Вопрос касался рефакторинга двух моделей, которые разделили функциональность. Достаточно общее требование и очень разумная вещь, которую я хочу сделать, но комментарии и решения заставили меня удивиться.
Это был вопрос, несколько отредактированный и переформатированный, чтобы сделать его более понятным
Я выделяю мясо класса ActiveRecord A в модуль M,
так что я могу дублировать некоторые конвейеры данных.
Исходная модель A имела макро-методы ActiveRecord, такие как own_to.
: Х
Несмотря на то, что я могу хорошо разделять не-AR вещи в модуле
и смешать его обратно в А, модуль ничего не знает о
принадлежат или что-то о AR модель B из коробки.
Как мне сделать их доступными для модуля, а затем смешать их обратно в
новый мелководный A, который теперь включает только M, и B, который является клоном
А со своей собственной таблицей AR? Или я должен что-то написать
как плагин act_as (верно?) вместо M? Сохранение принадлежит в
А и дублирование его в Б работает, но побеждает принцип СУХОГО
Что я не понял, так это то, почему человек, задающий вопрос, помещал этот код в модуль, а не в класс, из которого модели могли бы спуститься.
В Rails (почти) каждый класс происходит от другого класса, верно?
Вы видите код как
class MyModel < ActiveRecord::Base
повсюду. Хорошо, что :: Base может показаться немного загадочным, и я вижу, как это скрывает то, что здесь происходит, поэтому давайте посмотрим на пример контроллера
Все контроллеры выходят из ApplicationController при первом генерировании, верно?
Итак, вы получите
class MyController < ApplicationController
Сколько из вас поместили код в контроллер приложения, как до фильтров и текущих) пользовательских методов, и в конечном итоге использовали этот код в своих контроллерах и представлениях?
Если вы немного подумаете об этом, то увидите, что если вы поместите код в ApplicationController, который является открытым или защищенным, то все контроллеры, которые выходят из ApplicationController, получают эту функциональность, верно?
ApplicationController - это просто класс, который происходит от ActionController :: Base, определение выглядит следующим образом
class ApplicationController < ActionController::Base
Теперь это выглядит настолько знакомым, что вышеприведенное использование настолько распространено, что я начинаю думать, что многие разработчики Rails пытаются увидеть дрова для деревьев.
Это все о наследовании.
Rails помещает кучу методов в классы ActionController::Base
и ActiveRecord::Base
(вот и все, классы внутри модуля), так что вы можете наследовать свои собственные классы из этих классов, наследуя тем самым методы и функциональные возможности, предоставляемые этими базовыми классы.
Так почему бы не создать абстрактный класс ActiveRecord :: Base для решения проблемы. Это казалось мне наиболее очевидным и естественным подходом.
Я придумал это решение
In a_base_class.rb
class ABaseClass < ActiveRecord::Base
abstract true
has_many :whatevers
belongs_to :whatevers
def common_methods
#some code here
end
end
Then class a
class A < ABaseClass
# Whatever
end
Это может быть размещено внутри модуля для целей именования
Если вы хотите поместить это в модуль, тогда переходите от WhwhatModule :: ABaseClass, тогда это крутой способ разделения имен между новым базовым классом, чтобы имена классов не конфликтовали, и это является одной из основных целей использования модуль. Назвать космические классы.
Очевидно, используйте любые реальные имена классов, которые имеют для вас смысл.
@ Rishav Rastogi предоставил отличный ответ для использования модулей, и это то, что заставило меня по-настоящему задуматься, почему это решение не было настолько ясным для других и почему вопрос вообще был задан в первую очередь, и у меня сложилось впечатление, что люди действительно не знают, что на самом деле делает такой код
class SomeController < ApplicationController
и
class MyModel < ActiveRecord::Base
Когда это то, что разработчики Rails используют каждый день?
Это все о наследовании.
Абстрактные и неабстрактные классы все наследуются от одного класса, верно? Класс, наследуемый от, вполне может наследовать от ряда других классов, образующих единую цепочку наследования, но это все же единичное наследование. каждый класс происходит только от одного другого класса.
Так что же могут сделать модули, чтобы помочь?
Модули несколько запутанно используются для 2 целей.
1) Называть космические вещи как уже упоминалось
2) Предоставить сценарий множественного наследования. Множественное наследование - это грязное слово в мире разработки. Все может закончиться в правильном беспорядке, но модули обеспечивают довольно аккуратное решение.
Пример того, почему вы хотите множественное наследование
ActiveRecord :: Base предоставляет такие методы, как find_by_something и find.all, которые возвращают массив объектов ActiveRecord :: Base (классы - это объекты кода, которые являются реальными вещами)
Зная это, имеет смысл иметь наследование базового класса от класса массива, но если он это сделает, он не сможет наследовать от любого другого более подходящего класса. Решение состоит в том, чтобы смешать в модуле. Если модуль содержит класс массива, вы получаете весь функционал массива, такой как .each и .empty? плюс весь сок других классов, которые использует ActiveRecord :: Base.
Так когда же использовать модуль, а когда наследовать?
Использовать модуль для разделения имен (классы могут находиться внутри модуля)
Использовать класс для наследования
Так что используйте их вместе одновременно, если только вы не хотите множественного наследования, в этом случае просто используйте модули