модуль Module::Concerning
Разделение забот на небольшие части
Мы часто сталкиваемся со средним куском поведения, который мы хотели бы извлечь, но только смешиваем в один класс.
Извлечение обычного объекта Ruby для его инкапсуляции и сотрудничества или делегирования исходному объекту часто является хорошим выбором, но когда нет дополнительного состояния для инкапсуляции или мы делаем объявления в стиле DSL относительно родительского класса, введение новых коллабораторов может запутать, а не упростить.
Типичный путь — просто выбросить все в монолитный класс, возможно, с комментарием, как наименее плохой альтернативе. Использование модулей в отдельных файлах означает утомительное просеивание, чтобы получить общее представление.
Неудовлетворительные способы разделения небольших забот
Использование комментариев:
class Todo < ApplicationRecord
# Other todo implementation
# ...
## Event tracking
has_many :events
before_create :track_creation
private
def track_creation
# ...
end
end
С встроенным модулем:
Громкий синтаксис.
class Todo < ApplicationRecord
# Other todo implementation
# ...
module EventTracking
extend ActiveSupport::Concern
included do
has_many :events
before_create :track_creation
end
private
def track_creation
# ...
end
end
include EventTracking
end
Шум миксина, сосланный в собственный файл:
Когда кусок нашего поведения начинает выходить за пределы области прокрутки, чтобы понять его, мы сдаемся и перемещаем его в отдельный файл. При таком размере увеличение накладных расходов может быть разумным компромиссом, даже если это уменьшит наше восприятие того, как работают вещи.
class Todo < ApplicationRecord # Other todo implementation # ... include TodoEventTracking end
Представление Module#concerning
Успокаивая шум миксина, мы получаем естественный, простой способ разделить небольшие заботы.
class Todo < ApplicationRecord
# Other todo implementation
# ...
concerning :EventTracking do
included do
has_many :events
before_create :track_creation
end
private
def track_creation
# ...
end
end
end
Todo.ancestors
# => [Todo, Todo::EventTracking, ApplicationRecord, Object]
Этот небольшой шаг имеет некоторые замечательные побочные эффекты. Мы можем
-
понять поведение нашего класса с первого взгляда,
-
очистить монолитные классы-хранилища, разделяя их заботы, и
-
перестать полагаться на protected/private для грубой модульности «это внутренняя информация».
Добавление concerning в начало
concerning поддерживает аргумент prepend: true, который prepend заботу вместо использования include для неё.
Общедоступные методы экземпляров
# File activesupport/lib/active_support/core_ext/module/concerning.rb, line 132
def concern(topic, &module_definition)
const_set topic, Module.new {
extend ::ActiveSupport::Concern
module_eval(&module_definition)
}
end Короткий способ определения заботы.
concern :EventTracking do ... end
эквивалентно
module EventTracking extend ActiveSupport::Concern ... end
# File activesupport/lib/active_support/core_ext/module/concerning.rb, line 114 def concerning(topic, prepend: false, &block) method = prepend ? :prepend : :include __send__(method, concern(topic, &block)) end
Определение новой заботы и её добавление.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.