В настоящее время у меня есть код, подобный следующему (несколько упрощенный). Со временем я добавил все больше и больше новых классов, таких как D1 / D2, и я думаю, что пришло время провести некоторый рефакторинг, чтобы сделать его более элегантным. Цель курса - сделать так, чтобы добавление нового класса Dx использовало как можно меньше дублирующегося кода. По крайней мере, дублирующие части вызова FileImporter.import
внутри синглтон-метода Dx.import
должны быть исключены.
module FileImporter
def self.import(main_window, viewers)
...
importer = yield file # delegate to D1/D2 for preparing the importer object
...
end
end
class D1
def self.import(main_window)
viewers = [:V11, ] # D1 specific viewers
FileImporter.import(main_window, viewers) do |file|
importer = self.new(file)
... # D1 specific handling of importer
return importer
end
end
end
class D2
def self.import(main_window)
viewers = [:V21,:v22, ] # D2 specific viewers
FileImporter.import(main_window, viewers) do |file|
importer = self.new(file)
... # D2 specific handling of importer
return importer
end
end
end
# client code calls D1.import(...) or D2.import(...)
По существу, FileImporter.import
- это общая часть, а Dx.import
- это вариация. Я не уверен, как реорганизовать эти одноэлементные методы. Каков обычный Ruby способ сделать это?
Обновление : (некоторые комментарии были добавлены в вышеприведенный код, надеюсь, прояснить мою интенцию ...)
Первоначально я пропустил код, который я считал несущественным, чтобы избежать путаницы. Я должен был упомянуть, что приведенный выше код был также результатом рефакторинга классов D1 и D2 (путем перемещения общей части в модуль FileImporter
). Цель D1.import
и D2.import
состояла главным образом в создании объектов соответствующего класса (и, возможно, после некоторой обработки, специфичной для класса, перед возвратом из блока). FileImporter.import
- это, в основном, общая логика, в рамках которой в некоторый момент может быть получен определенный класс для генерации объекта импортера.
Я чувствую, что классы D1 и D2 выглядят действительно одинаково, и должна быть возможность их дальнейшего рефакторинга. Например, они оба вызывают FileImporter.import
для предоставления блока, внутри которого оба создают свой объект.
Решение : Изначально я не осознавал, что можно вызывать одноэлементные методы базового класса, просто вызывая super
из соответствующих одноэлементных методов производного класса. Это была действительно главная проблема, с которой я столкнулся и не смог пойти по этому пути. Поэтому я принял ответ @makevoid, поскольку он действительно облегчает создание новых производных классов.
Использование общего базового класса - элегантное решение для рефакторинга, но одной из проблем является то, что все новые производные классы уже используют одну квоту базового класса. Я пришел к этому макро-методу класса, который дает еще более краткие результаты с точки зрения производного класса.
module FileImporter
def self.included(mod)
mod.extend ClassMethods
end
module ClassMethods
def importer_viewer(*viewers, &blk)
@viewers = viewers
@blk = blk
class << self
def import(main_window)
if @blk.nil?
FileImporter.import(main_window, @viewers) do |file|
self.new(file)
end
else
FileImporter.import(main_window, @viewers, &@blk)
end
end
end
end
end
def self.import(main_window, viewers, multi=true)
...
importer = yield file # delegate to D1/D2 for preparing the importer object
...
end
end
class D1
include FileImporter
importer_viewer [:V11, ] do
... # D1 specific handling of importer
end
end
class D2
include FileImporter
importer_viewer [:V21,:v22, ] do
... # D2 specific handling of importer
end
end