Привет, друзья. С вами Alex Versus.
Ранее мы говорили про шаблоны проектирования Одиночка и Стратегия, про тонкости реализации на языке Golang.
Сегодня расскажу про Фабричный метод.
В чем суть?
Фабричный метод (Factory method) также известный как Виртуальный конструктор (Virtual Constructor) - пораждающий шаблон проектирования, определяющий общий интерфейс создания объектов в родительском классе и позволяющий изменять создаваемые объекты в дочерних классах.
Шаблон позволяет классу делегировать создание объектов подклассам. Используется, когда:
Классу заранее неизвестно, объекты каких подклассов ему нужно создать.
Обязанности делегируются подклассу, а знания о том, какой подкласс принимает эти обязанности, локализованы.
Создаваемые объекты родительского класса специализируются подклассами.
Какую задачу решает?
Представьте, что вы создали программу управления доставкой еды. В программе в качестве единственного средства доставки используется электро-самокат. Ваши курьеры на электро-самокатах развозят еду из пункта А в пункт Б. Все просто.
Программа набирает популярность и ваш бизнес растет. Парк самокатов ограничен и вы решаете подключить к вашей системе доставки велосипеды, такси, квадрокоптеры и роботов-курьеров. Вам важно знать когда будет доставлена еда и сколько единиц продуктов может забрать курьер. У новых транспортных средств разная скорость и вместимость.
Вы обнаруживаете, что большая часть ваших сущностей в программе сильно связаны с объектом Самокат и чтобы заставить вашу программу работать с другими способами доставки, вам придется добавить связи в 80% вашей кодовой базы и так повторить для каждого нового транспорта. Знакомая ситуация?
В итоге вы получите ужасающий код, наполненный условными операторами, которые выполняют то или иное действие, в зависимости от транспорта.
И какое решение?
Фабричный метод предлагает создавать объекты транспорта через вызов специального метода. Подклассы класса, который содержит фабричный метод могут изменять создаваемые объекты конкретных создаваемых транспортов. На первый взгляд, это может показаться бессмысленным: мы просто переместили вызов конструктора из одного конца программы в другой. Но теперь вы сможете переопределять фабричный метод в подклассе, чтобы изменить тип создаваемого транспорта.
Чтобы такая система заработала, все возвращаемые объекты имеют общий интерфейс, а подклассы могут производить объекты различных классов, имеющих общий интерфейс.
Для клиента фабричного метода нет разницы между создаваемыми объектами, так как он трактует их как некий абстрактный Транспорт. Для него важно, чтобы данный объект мог доставить еду из пункта А в пункта В, а как конкретно он это будет делать, неважно.
Посмотрим на диаграмму классов такого подхода.
![Диаграмма классов Factory Method Диаграмма классов Factory Method](https://habrastorage.org/getpro/habr/upload_files/498/d27/afb/498d27afbeb6c258daaa1010ae391590.png)
Реализация на Golang
Пример реализации на PHP, можно изучить тут. Так как в Golang отсутствуют возможности ООП, такие как классы и наследование, то реализовать в классическом виде этот шаблон невозможно. Несмотря на это, мы можем реализовать базовую версию шаблона - Простая фабрика.
В нашем примере есть файл iTransport.go, который определяет методы создаваемых транспортных средств для доставки еды. Сущность транспорта будем хранить в структуре (struct), которая применяет интерфейс iTransport.
Также реализуем файл Factory.go, который представляет фабрику создания нужных объектов. Клиентский код реализован в файле main.go. Вместо прямого создания конкретных объектов транспорта клиентский код будет использовать для этого метод фабрики getTransport(t string)
, передавая нужный тип объекта в виде аргумента функции.
Когда применять?
Когда хотим дать возможность расширять нашу библиотеку. Используя подход, пользователи вашей библиотеки могут создавать новые конкретные реализации классов, а создание объектов данных классов будет отведено фабричному методу вашей библиотеки.
Фабричный метод отделяет код создания объектов от остального кода. Код создания объектов можно расширять, не трогая основной код программы. Для создания нового объекта вашего продукта достаточно создать новый подкласс и определить в нем фабричный метод, возвращающий нужный продукт в нужной конфигурации.
Какие преимущества?
Избавляет слой создания объектов от конкретных классов продуктов. Выделяет код производства продуктов в одно место, упрощая поддержку кода.
Упрощает добавление новых продуктов в программу.
Реализует принцип открытости/закрытости (англ. open–closed principle, OCP) — принцип ООП, устанавливающий следующее положение: «программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения»
Какие недостатки?
Может привести к созданию больших параллельных иерархий классов, так как для каждого класса продукта надо создать свой подкласс создателя.
Итог
Используйте шаблон Фабричный метод в случае, когда вы хотите без проблем внедрять в вашу программу новые объекты с новыми конфигурациям для взаимодействия с основной бизнес-логикой.
Рад был поделиться материалом, Alex Versus. Публикация на английском.
Всем удачи!