
Фабричный метод на Ruby
Фабричный метод — это порождающий паттерн проектирования, который решает проблему создания различных продуктов, без указания конкретных классов продуктов.
Фабричный метод задаёт метод, который следует использовать вместо вызова оператора new
для создания объектов-продуктов. Подклассы могут переопределить этот метод, чтобы изменять тип создаваемых продуктов.
Сложность:
Популярность:
Применимость: Паттерн можно часто встретить в любом Ruby-коде, где требуется гибкость при создании продуктов.
Признаки применения паттерна: Фабричный метод можно определить по создающим методам, которые возвращают объекты продуктов через абстрактные типы или интерфейсы. Это позволяет переопределять типы создаваемых продуктов в подклассах.
Концептуальный пример
Этот пример показывает структуру паттерна Фабричный метод, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.rb: Пример структуры паттерна
# Класс Создатель объявляет фабричный метод, который должен возвращать объект # класса Продукт. Подклассы Создателя обычно предоставляют реализацию этого # метода. # # @abstract class Creator # Обратите внимание, что Создатель может также обеспечить реализацию # фабричного метода по умолчанию. # # @abstract def factory_method raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end # Также заметьте, что, несмотря на название, основная обязанность Создателя не # заключается в создании продуктов. Обычно он содержит некоторую базовую # бизнес-логику, которая основана на объектах Продуктов, возвращаемых # фабричным методом. Подклассы могут косвенно изменять эту бизнес-логику, # переопределяя фабричный метод и возвращая из него другой тип продукта. # # @return [String] def some_operation # Вызываем фабричный метод, чтобы получить объект-продукт. product = factory_method # Далее, работаем с этим продуктом. "Creator: The same creator's code has just worked with #{product.operation}" end end # Конкретные Создатели переопределяют фабричный метод для того, чтобы изменить # тип результирующего продукта. class ConcreteCreator1 < Creator # Обратите внимание, что сигнатура метода по-прежнему использует тип # абстрактного продукта, хотя фактически из метода возвращается конкретный # продукт. Таким образом, Создатель может оставаться независимым от конкретных # классов продуктов. # # @return [ConcreteProduct1] def factory_method ConcreteProduct1.new end end class ConcreteCreator2 < Creator # @return [ConcreteProduct2] def factory_method ConcreteProduct2.new end end # Интерфейс Продукта объявляет операции, которые должны выполнять все конкретные # продукты. # # @abstract class Product # return [String] def operation raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end # Конкретные Продукты предоставляют различные реализации интерфейса Продукта. class ConcreteProduct1 < Product # @return [String] def operation '{Result of the ConcreteProduct1}' end end class ConcreteProduct2 < Product # @return [String] def operation '{Result of the ConcreteProduct2}' end end # Клиентский код работает с экземпляром конкретного создателя, хотя и через его # базовый интерфейс. Пока клиент продолжает работать с создателем через базовый # интерфейс, вы можете передать ему любой подкласс создателя. # # @param [Creator] creator def client_code(creator) print "Client: I'm not aware of the creator's class, but it still works.\n"\ "#{creator.some_operation}" end puts 'App: Launched with the ConcreteCreator1.' client_code(ConcreteCreator1.new) puts "\n\n" puts 'App: Launched with the ConcreteCreator2.' client_code(ConcreteCreator2.new)
output.txt: Результат выполнения
App: Launched with the ConcreteCreator1. Client: I'm not aware of the creator's class, but it still works. Creator: The same creator's code has just worked with {Result of the ConcreteProduct1} App: Launched with the ConcreteCreator2. Client: I'm not aware of the creator's class, but it still works. Creator: The same creator's code has just worked with {Result of the ConcreteProduct2}