Привет, Хабр! Представляю вашему вниманию перевод очередной статьи «Design Patterns: Abstract Factory Pattern» автора Shubham Zanwar.
Абстрактная фабрика — это порождающий шаблон проектирования. Он используется, когда нам нужно создать семейство похожих продуктов. Давайте для понимания возьмем пример сети пиццерий.
Пиццерия
Представим, что вы глава бизнеса и открываете сеть пиццерий по всему городу. Одной из ваших обязанностей является производство всех основных продуктов (в нашем случае это пиццы и жареный чесночный хлеб), которые будут представлять такие бренды как Домино и Жаровня (назовем их так — прим. перев.).
Есть множество способов как это сделать. Самый простой — создать фабрику по производству пицц каждого бренда и еще похожую фабрику для жаренного хлеба.
Если вы еще не представляете, как работают фабрики, вы можете почитать здесь
Проблема в том, что теперь мы доверяем пользователю выбор правильного типа пиццы и жаренного хлеба, который они хотят. Если они сделают ошибку в приготовлении пиццы Домино с чесночным хлебом Жаровни, ваши заказчики будут в ярости и вы можете потерять контракт с сетями этих брендов.
Не волнуйтесь, есть простой способ.
Вместо создания фабрики для каждого продукта (пиццы или жаренного хлеба), вы сможете создавать фабрику для каждого бренда. Обе фабрики будут производить пиццу и жареный хлеб.
Открыв пиццерию, вы передаете менеджеру фабрику Домино или Жаровню и можете отдохнуть, потому что теперь никто ничего не перепутает.
Давайте посмотрим на код. Перед тем как мы напишем фабрики, создадим сами продукты:
Обычная пицца
type iPizza interface { GetPrice() float64 GetName() string GetToppings() []string } type pizza struct { name string price float64 toppings []string } func (p *pizza) GetName() string { return p.name } func (p *pizza) GetPrice() float64 { return p.price } func (p *pizza) GetToppings() []string { return p.toppings }
Пиццы наших брендов
type pizzaHutPizza struct { pizza } type dominosPizza struct { pizza }
Жареный чесночный хлеб
type iGarlicBread interface { GetPrice() float64 GetName() string } type garlicBread struct { name string price float64 } func (g *garlicBread) GetName() string { return g.name } func (g *garlicBread) GetPrice() float64 { return g.price }
И наших брендов
type pizzaHutGarlicBread struct { garlicBread } type dominosGarlicBread struct { garlicBread }
Мы создали оба наших продукта, которые реализуют общий интерфейс, облегчая конечному пользователю их потребление. Вот такой каламбур.
Теперь напишем сами фабрики, сначала общая
type iPizzaFactory interface { createPizza() iPizza createGarlicBread() iGarlicBread }
Теперь наших брендов: Жаровня-фабрика и Домино-фабрика с унифицированной функциональностью
type PizzaHutFactory struct {} func (p *PizzaHutFactory) createPizza(): iPizza { return &pizzaHutPizza{ pizza{ name: "pepperoni", price: 230.3, toppings: []string{"olives", "mozzarella", "pork"}, }, } } func (p *pizzaHutFactory) createGarlicBread() iGarlicBread { return &pizzaHutGarlicBread{ garlicBread{ name: "garlic bread", price: 180.99, }, } }
type dominosFactory struct{} func (d *dominosFactory) createPizza() iPizza { return &dominosPizza{ pizza{ name: "margherita", price: 200.5, toppings: []string{"tomatoes", "basil", "olive oil"}, }, } } func (d *dominosFactory) createGarlicBread() iGarlicBread { return &dominosGarlicBread{ garlicBread{ name: "cheesy bread sticks", price: 150.00, }, } }
Мы можем выбирать любую фабрику и продолжить приготовление пиццы или жаренного хлеба и быть абсолютно уверенными, что любой производный продукт будет соответствующего семейства/бренда.
Мы почти у цели. Давайте обернем это в фабрику, которая будет возвращать нам фабрику по нашему желанию. Сбиты с толку? Тогда еще раз прочитайте предыдущее предложение.
Думайте о наших фабриках как о другом объекте. Основываясь на типе или пиццерии, которые мы хотим открыть (Жаровня или Домино), мы создаем нужную фабрику (просто другой объект). Чтобы автоматически получать эти «объекты», у нас будет своя фабрика.
Этот код поможем вам — Фабрика фабрик
func getPizzaFactory(chain string) (iPizzaFactory, error) { if chain == "P" { return &pizzaHutFactory{}, nil } if chain == "D" { return &dominosFactory{}, nil } return nil, fmt.Errorf("Enter a valid chain type next time") }
Надеюсь, стало понятнее.
Основное, что нужно запомнить: шаблон абстрактная фабрика реализует фабрику фабрик. Внутренние фабрики используются для создания продуктов нужного вида.
Вы можете найти этот код на github
Пока
ссылка на оригинал статьи https://habr.com/ru/post/530096/
Добавить комментарий