Я обдумываю один из двух разных способов реализации фабричного шаблона в 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 не имеет концепции пакетов и уровня защиты «пакет» для членов класса. Это означает, что ничто не мешает кодеру просто выполнить new Foo () и обойти фабрику (хотя это может упростить модульное тестирование).
Другая проблема заключается в том, что FooFactory может создавать только объекты Foo, а не какие-либо его подклассы. Это можно обойти, добавив еще один параметр в FooFactory, чтобы указать имя класса, но тогда фабрика должна будет выполнить внутренние проверки того, что указанный объектный класс на самом деле является потомком Foo.
Итак, каковы относительные достоинства этих двух подходов и какой из них вы бы порекомендовали?
Кроме того, если у них больше имен собственных, чем у внутренней или внешней фабрики, я бы хотел их узнать.