Я размышляю об одном из двух разных способов реализации фабричного шаблона в PHP. Я не знаю, имеют ли эти варианты собственные имена, поэтому сейчас я назову их внутренней фабрикой и внешней фабрикой.
Внутренняя фабрика: фабричный метод реализован в самом классе как статический публичный метод
<?php
class Foo
{
protected
$loadedProps = false;
public static factory ($id)
{
$class = get_called_class ();
$item = new $class ($id);
if ($item -> loadedProps ())
{
return ($item);
}
}
public function loadedProps ()
{
return ($this -> loadedProps);
}
protected function loadPropsFromDB ($id)
{
// Some SQL logic goes here
}
protected function __construct ($id)
{
$this -> loadedProps = $this -> loadPropsFromDB ($id);
}
}
?>
Внешняя фабрика: фабрика и элементы, которые она инициализирует, реализованы как отдельные объекты
<?php
class Foo
{
protected
$loadedProps = false;
public function loadedProps ()
{
return ($this -> loadedProps);
}
protected function loadPropsFromDB ($id)
{
// Some SQL logic goes here
}
public function __construct ($id)
{
$this -> loadedProps = $this -> loadPropsFromDB ($id);
}
}
abstract class FooFactory
{
public static factory ($id)
{
$item = new Foo ($id);
if ($item -> loadedProps ())
{
return ($item);
}
}
}
?>
Теперь мне кажется, что у каждого есть свои достоинства.
Первый позволяет скрыть конструктор от внешнего мира. Это означает, что единственный способ создать объект Foo - через фабрику. Если состояние элемента не может быть загружено из БД, то фабрика вернет NULL, что вы можете легко проверить в коде.
if ($item = Foo::factory ($id))
{
// ...
}
else
{
// The item failed to load. Handle error here
}
Фабрика также может создавать объекты любого подкласса Foo без каких-либо изменений.
Однако, похоже, есть некоторые недостатки. Во-первых, класс должен реализовать фабрику, которая может накладывать обязанности на класс, которые действительно принадлежат другому месту. Внутренняя заводская версия, безусловно, дает больший класс, чем внешняя заводская версия.
Что касается внешней фабрики, то она чище, поскольку фабрика не относится к самому классу, и мне не нужно беспокоиться о том, чтобы класс взял на себя больше ответственности, чем следовало бы. Внешняя фабрика также может лучше подходить для внедрения зависимостей.
Однако у него есть свой набор недостатков. Прежде всего, конструктор элемента, который будет построен на фабрике, должен быть общедоступным, поскольку в PHP нет концепции пакетов и нет уровня защиты «пакета» для членов класса. Это означает, что ничто не мешает программисту просто выполнять новый Foo () и обходить фабрику (хотя это может упростить модульное тестирование).
Другая проблема заключается в том, что FooFactory может создавать только объекты Foo, но не любые его подклассы. Эту проблему можно обойти, добавив другой параметр в FooFactory для указания имени класса, но тогда фабрика должна будет выполнить внутренние проверки того, что указанный объектный класс на самом деле является потомком Foo.
Итак, каковы относительные достоинства двух подходов и что бы вы порекомендовали?
Кроме того, если у них больше имен собственных, чем у внутренней или внешней фабрики, я бы хотел их знать.