Задать вопрос
Этот вопрос закрыт для ответов, так как повторяет вопрос Как реализовать фабричный метод без switch?
@random55

Фабричный метод, как использовать?

Реализация паттерна понятна, но не совсем понятно в каких ситуациях использовать. Поясню:
Паттерн позволяет определить в потомках создающего класса какой конкретно экземпляр из множества объектов реализующих единый интерфейс нам необходимо создать. Но я видел разные примеры применения, и не улавливаю основной сути.

1. В некоторых источниках объект класса создателя используется исключительно для порождения. У нас есть некоторый клиентский код, изначально неизвестно какой именно объект в него придёт, известно лишь то какой у него интерфейс.
interface SomeInterface {
    public function baz();
}

class Foo implements SomeInterface {
    public function baz() {
        // ... 
    }
}

class Bar implements SomeInterface {
    public function baz() {
        // ... 
    }
}

abstract class Creator {
    abstract public function create(): SomeInterface;
}

class FooCreator {
    public function create(): SomeInterface {
        return new Foo();
    }
}

class BarCreator {
    public function create(): SomeInterface {
        return new Bar();
    }
}

function client_code(Creator $creator) {
    $some = $creator->create();

    $some->baz();

    // ...
}


Структура ясна, но вот только зачем лишняя обёртка в виде класса-создателя, если мы можем в клиентском коде принимать параметр непосредственно типа SomeInterface (при этом сохраняется полиморфизм, принцип открытости-закрытости не нарушается), и создавать нужный объект где-нибудь в Dependency Injection контейнере или на уровне вызова client_code()? Ведь в любом случае нам нужно как-то определить какого конкретного создателя инстанцировать, а значит код в том же DiC или выше client_code будет присутствовать, так зачем нужен посредник?

function client_code(SomeInterface $some) {
    $some->baz();
}


2. Ещё видел варианты, когда объект Creator это не просто порождающий объект, а некоторый класс выполняющий помимо этого некоторую другую работу, в которой он как раз таки и использует этот самый объект типа SomeInterface, а сам фабричный метод вообще protected.

interface SomeInterface {
    public function baz();
}

class Foo implements SomeInterface {
    public function baz() {
        // ... 
    }
}

class Bar implements SomeInterface {
    public function baz() {
        // ... 
    }
}

abstract class NotJustACreator {
    public function doSomething() {
        $some = $this->create();
        $some->baz();
        // ...
    }

    abstract protected function create(): SomeInterface;
}

class FooNotJustACreator {
    protected function create(): SomeInterface {
        return new Foo();
    }
}

class BarNotJustACreator {
    protected function create(): SomeInterface {
        return new Bar();
    }
}


Но этот вариант ещё более непонятен, зачем выносить какой-либо функционал в отдельный объект, если у нас на каждый подтип создаваемого объекта будет свой NotJustACreator, и каждый его потомок создаёт ровно 1 конкретный подтип? Почему бы функционал создаваемого объекта не сделать просто частью NotJustACreator, а нужный NotJustACreator создавать так же в Dependency Injection контейнере или где-либо ещё?

В чём профит?
  • Вопрос задан
  • 217 просмотров
Подписаться 1 Простой
Решения вопроса 1
1. Это не фабричный метод, а фабрика
2. При наличии DI обычно он не нужен, как правильно вы заметили. Можно сразу засунуть нужный объект.

Такое может быть нужно, например, если какие-то параметры для создаваемого объекта становятся известны лишь в процессе выполнения.
Или если не известно заранее, нужен ли будет вообще этот объект, а его создание дорогое.
Или если просто невозможно его создать через DI, например если инициализация асинхронная, которую DI может не поддерживать.

Или если нужно много таких объектов.
Например у тебя может быть сервис для отправки почты, и несколько разных шаблонов письма. Ты можешь в этот сервис передать фабрику, которая создаст нужный шаблон
Ответ написан
Ваш ответ на вопрос

Вопрос закрыт для ответов и комментариев

Потому что уже есть похожий вопрос.
Похожие вопросы