Абстрактная фабрика: способы реализации

Сейчас я изучаю шаблоны проектирования и читаю разные ресурсы по каждому шаблону. У меня вопрос по паттерну Abstract Factory. Я читал о двух способах реализации этого. Напишу с использованием этой фабрики, без реализации. Я, например, взял разные двери.

Первый способ. У нас есть общий класс для Door Factory, который состоит из разных методов для создания разных типов дверей (который возвращает соответствующий класс двери):

$doorFactory = new DoorFactory();
$door1 = $doorFactory->createWoodDoor();

$doorFactory = new DoorFactory();
$door2 = $doorFactory->createSteelDoor();

Второй способ. У нас есть родительский класс DoorFactory и расширяет классы для WoodDoorFactory и SteelDoorFactory. Эти классы реализуют тот же метод createDoor (и возвращают соответствующий класс Door)

$woodDoorFactory = new WoodDoorFactory();
$door1 = $woodDoorFactory->createDoor();

$steelDoorFactory = new SteelDoorFactory();
$door2 = $steelDoorFactory->createDoor();

Как вы думаете, какой путь оптимальнее и каноничнее?

В PHP
В PHP
В большой кодовой базе с множеством различных компонентов классы, функции и константы могут иметь одинаковые имена. Это может привести к путанице и...
Принцип подстановки Лискова
Принцип подстановки Лискова
Принцип подстановки Лискова (LSP) - это принцип объектно-ориентированного программирования, который гласит, что объекты суперкласса должны иметь...
0
0
104
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Представьте, пожалуйста, ситуацию, когда ваша фабрика проходит мимо, и какой клиентский код должен запросить фабрику, просто создает дверь (не заботясь о дереве и стали), вы поймете, почему второй способ лучше. Допустим, у нас есть класс Client с методом foo, который использует фабрику (я использую Java, но это должно быть легко понять):

class Client {
    private DoorFactory factory;
    public Client(DoorFactory factory) { this.factory = factory; }
    public void foo() {
        Door door = factory.createDoor();
    }
}

Теперь вы можете передать WoodDoorFactory, SteelDoorFactory или WhateverDoorFactory конструктору Client.

Более того, не говоря уже о том, что ваш 1-й способ может быть нарушением Принципы единой ответственности, поскольку класс DoorFactory знает много вещей, которые, вероятно, не связаны. Действительно, он знает, как создать деревянную дверь, для которой требуется Wood APIs (просто пример), он знает, как создать стальную дверь, для которой требуется Steel APIs. Это явно снижает возможность повторного использования класса DoorFactory в другой среде, которая не хочет зависеть от Wood APIs или Steel APIs. Эта проблема не возникает с вашим 2-м способом.

Как и в случае с другими ответами, я также обычно предпочитаю второй метод на практике. Я обнаружил, что это более гибкий и полезный подход для внедрения зависимостей.

Тем не менее, я думаю, что есть случаи, когда первый подход работает так же хорошо, если не лучше - они просто не так распространены. На ум приходит пример объектной модели XML-документа. Если вы когда-либо использовали Microsoft C++ XML DOM Document API, то вы знакомы с этим подходом (см. https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms760218(v%3dvs.85)).

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

Другое преимущество в этом случае состоит в том, что, сделав класс XML-документа фабрикой для всех содержащихся в нем элементов, XML-документ имеет полный контроль над временем жизни этих внутренних объектов. ПРИМЕЧАНИЕ. Они запрещают использование одних и тех же подэлементов в нескольких экземплярах XML-документа. Если вы хотите использовать узел из одного XML-документа и поместить его в другой XML-документ, вам потребуется пройти через второй XML-документ, чтобы создать новый элемент узла, а также копию всех без исключения подэлементов.

Заметное отличие в этом случае от примера в OP состоит в том, что вместо использования Factory Method для предоставления нескольких способов создания одного и того же типа вещей здесь Factory знает, как создать кучу очень связанных (и связанных) объектов. типы.

Другие вопросы по теме