Шаблоны проектирования в Go — Абстрактная Фабрика

от автора

Привет, Хабр! Представляю вашему вниманию перевод очередной статьи «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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *