В чем преимущество использования шаблона фабричного метода по сравнению с простым фабричным методом?

Я читаю о шаблоне фабричного метода и простой фабрике. Как я понимаю, простой фабрики достаточно, и я не вижу варианта использования паттерна фабричного метода. Прочтите эту ссылку, https://www.binpress.com/factory-design-pattern/, и я буду задавать свои вопросы.

1) в простой фабрике говорит, что это плохо, потому что нарушает принцип открыт / закрыт. Я понимаю это, но в шаблоне фабричного метода то, что он делал, по-прежнему нарушает принцип открытого / закрытого.

if ('car'==$toyName) {
            $toy = new NyCar();
        } else if ('helicopter'==$toyName) {
            $toy = new NyHelicopter();
        }

Если будет новая история для Нью-Йорка, нам нужно добавить ее сюда.

2) после прочтения ссылки, прежде чем она действительно достигла лучшего решения, он использовал следующий код. :

class NySimpleFactory {
    public function createToy($toyName) {
        $toy = null;

        if ('car'==$toyName) {
            $toy = new NyCar();
        } else if ('helicopter'==$toyName) {
            $toy = new NyHelicopter();
        }

        return $toy;
    }
}

class NyToysFactory {

    public $simpleFactory;

    public function __construct(SimpleFactory $simpleFactory) {
        $this->simpleFactory = $simpleFactory;
    }

    public function produceToy($toyName) {
        $toy = null;
        $toy = $this->simpleFactory->createToy($toyName);
        $toy->prepare();
        $toy->package();
        $toy->label();
        return $toy;
    }
}

Затем он говорит:

Разработчики быстро дорабатывают новый код и передают его фабрикам в США. Через две недели в офисе разработчиков начинает звонить телефон, потому что на заводе в Нью-Йорке возникли проблемы с производством. Оказывается, класс NyToysFactory был изменен разработчиками в удаленном филиале, потому что персонал не хочет выполнять работу по упаковке и маркировке. Они изменили produToy (), удалив его функции label () и package ().

Похоже, что Simple Factory в этом случае не сработает. Мы не хотим, чтобы филиалы в США могли изменять функции produToy (). ProduceToy () должен состоять из набора стандартных процедур, а ветви должны отвечать только за создание игрушек для конкретных мест. Что, если они могут создать абстрактный класс? И созданный ими абстрактный класс будет иметь конкретный метод produToy (), который будет реализовывать набор стандартных рабочих процедур, которым должны следовать все ветви. Внутри produToy () он вызывает собственный абстрактный метод createToy () для получения игрушечного класса. Таким образом createToy () может инкапсулировать создание объекта и, поскольку он абстрактный, делегирует создание своим подклассам.

Вопрос: а) Что это значит, когда говорится о передаче фабрики в США? б) или Мы не хотим, чтобы филиалы в США могли изменять функции produToy (). они все еще могут изменять функцию produToy, какая разница, если они не могут или могут ее изменить? Я просто не понимаю, почему простой завод вообще плох для следующего примера.

Не нужно читать об абстрактной фабрике по этой ссылке


person Nika Kurashvili    schedule 19.11.2018    source источник


Ответы (1)


T ЕГО КОД / ПРОБЛЕМА не освещает абстрактную фабрику или фабричный метод. Решение, какой класс создать, включив параметр, действительно является анти-паттерном, поощряющим нарушение принципа открытого-закрытого.

Абстрактная фабрика

Абстрактная фабрика - это реализация семейства связанных классов:

abstract class ToyFactory
+ createBear(): ToyBear
+ createElephant(): ToyElephant

class USToyFactory extends ToyFactory
+ createBear(): ToyBear -> creates USToyBear
+ createElephant(): ToyElephant -> USToyElephant

abstract class ToyBear
+ playSound()

class USToyBear extends ToyBear
+ playSound()//play US National Anthem

Передача USToyFactory, где ожидается ToyFactory, приводит к созданию американских игрушек (USToyBear и USToyElephant), в этом заключается сила Abstract Factory.

Обратите внимание, что продукты, медведи, слоны и т. д. известны AoT (заранее).

Заводской метод

Фабричный метод заключается в том, чтобы отложить создание экземпляров до подклассов.

abstract class Dashboard
+ createWidget(): Widget

abstract class Widget
+ config()

class StatsDashboard extends Dashboard
+ createWidget: Widget -> return new StatsWidget()

class StatsWidget extends Widget

Вызов createWidget () возвращает виджет, но возвращаемый конкретный виджет должен быть отложен до подклассов (StatsDashboard возвращает StatsWidget).

Обратите внимание, что методы создания объявлены наверху дерева наследования, но выполняются вниз по дереву наследования.

❧ Внимательный читатель увидит, что методы абстрактной фабрики похожи на методы фабрики, совпадение? нет. Отсюда и происходит имя фабричных методов (они выполняют создание конкретного класса).

Путаница относительно заводов в США действительна; это плохой выбор слов. Автор намекает, что этот код может быть передан заводским рабочим, что совершенно не имеет отношения к заводским шаблонам и сбивает с толку.


Чтобы разрешить описанный выше переключатель, вам необходимо осознать очевидное: каждый обработчик условий каким-то образом связан. В данном случае это все игрушки.

public function createToy($toyName) {
    $toy = null;

    if ('car'==$toyName) {
        $toy = new NyCar();//I'm a Toy
    } else if ('helicopter'==$toyName) {
        $toy = new NyHelicopter();//I'm a Toy
    }

    return $toy;
}

Используя полиморфизм, мы можем удовлетворить принципу открытости-закрытости, создав набор родственных классов:

abstract class Toy
+ operate()

Car extends Toy

Helicopter extends Toy

some_toy.operate();

Добавление к корпусам переключателей - это не что иное, как создание еще одного родственного класса.

Надеюсь, это поможет!

person Rafael    schedule 19.11.2018
comment
Спасибо, Рафаэль. Мы поговорим о разнице между фабричным методом и простой фабрикой. Я могу делать что угодно с простой фабрикой, зачем вообще использовать фабричный метод? - person Nika Kurashvili; 19.11.2018
comment
Фабричный метод заключается в том, чтобы отложить создание экземпляров до подклассов. Это важно, когда вы создаете интерфейсы, которые создают объекты, но не можете предсказать, какие объекты будут созданы. - person Rafael; 19.11.2018
comment
Можем ли мы обсудить это в приватном чате или что-то в этом роде? Я многое узнал об этом шаблоне, но все еще меня как-то смущает. Вопросы, которые у меня есть, займут здесь много времени. заранее спасибо - person Nika Kurashvili; 19.11.2018
comment
Итак, вместо того, чтобы использовать switch (if/else) и позволить createToy выбирать подкласс, мы должны передать подкласс в качестве аргумента и просто позволить createToy создать его экземпляр? - person papiro; 19.11.2018
comment
@Rafael Если фабричный метод полагается на DI вместо некоторого параметра, переданного переключателю, как в простой фабрике, как он используется в качестве фабрики, которая может производить различные продукты во время выполнения? Разве фабричный метод никогда не использует переключатель или некоторую управляющую логику, чтобы решить, какой гордый продукт или создатель продукта создать? Если это похоронено в контейнере DI, как бы вы могли заставить этот контейнер возвращать разные типы экземпляров для одного и того же интерфейса? - person Ε Г И І И О; 15.05.2020
comment
@ ΕГИІИО Я удалил оператор DI, так как он сбивал с толку. Однако фабричный метод знает, какой продукт создать, просто вызывая его через одну отправку. - person Rafael; 15.05.2020
comment
@ ΕГИІИО Да, клиенту потребуется управляющая логика, чтобы решить, какой класс (с фабричным методом) создать, но эта управляющая логика абсолютно не должна присутствовать ни в каких фабричных методах. Это противоречит цели шаблона проектирования. - person Rafael; 15.05.2020
comment
@Rafael Хм, если я правильно понял, когда вы реализуете фабричный метод, вам все равно понадобится простая фабрика (или подобный код) на клиенте, чтобы раскрутить вещи. Вы встречали какой-нибудь образец кода, показывающий это подключение? наверное без части DI? Фабричный метод меня каждый раз сбивает с толку. - person Ε Г И І И О; 15.05.2020
comment
@ ΕГИІИО Именно. Имейте в виду, что это всего лишь пример полиморфизма и не более того. Это просто обычный случай использования полиморфизма, достойный названия. Основная идея полиморфизма состоит в том, чтобы код был универсальным, а значит, можно было использовать повторно, чтобы клиентам не нужно было знать, с чем они работают. Это позволяет нам доводить до клиентов конкретные решения, так что в итоге мы получаем общее ядро ​​и небольшую конкретную оболочку (являющуюся неуниверсальным аспектом кода). - person Rafael; 16.05.2020
comment
@ ΕГИІИО Вы действительно хотите иметь значительное общее ядро; это означает, что вы получаете много повторного использования. Кроме того, общий код можно извлечь в библиотеку. Я сомневаюсь в коде, который имеет толстую оболочку, не допускающую повторного использования, потому что, давайте посмотрим правде в глаза, большая часть кода делает то же самое (более или менее), и редко что-то что отличается. - person Rafael; 16.05.2020
comment
@ ΕГИІИО Тем не менее, это не означает, что все, что может быть общим, должно быть универсальным. Это привело бы к ненужному увеличению сложности, т. Е. К чрезмерной инженерии. Это зависит от цели, предметной области и варианта использования, например, что может измениться со временем, и т. Д. И т. Д. ... Большинство абстракций лучше отложить до времени, в котором они необходимы, т. Е. Вводить органически, по запросу. , а не с нетерпением. - person Rafael; 16.05.2020