Реализация паттерна понятна, но не совсем понятно в каких ситуациях использовать. Поясню:
Паттерн позволяет определить в потомках создающего класса какой конкретно экземпляр из множества объектов реализующих единый интерфейс нам необходимо создать. Но я видел разные примеры применения, и не улавливаю основной сути.
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 контейнере или где-либо ещё?
В чём профит?