Шаблон Factory Method (Фабричный метод) на PHP
03-07-2019Время чтения ~ 2 мин.PHP/ООП 9507
Factory Method (Фабричный метод) немного похож на Абстрактную фабрику. Он также позволяет спрятать конкретную реализацию и предоставить несколько типовых методов для использования.
Но, о отличие от абстрактной фабрики, фабричный метод даёт возможность задать какой именно класс «реализации» использовать в конкретной фабрике.
Исходный код шаблона вы найдете на гитхабе.
Существует несколько вариантов реализации Factory Method, я остановился на статическом методе. На самом деле это не обязательно, можно использовать и обычные методы, хотя это увеличит размер кода.
Итак. У фабрик должен быть единый интерфейс. Для этого мы используем абстрактный класс CommonAbstract, который сам может содержать обязательные методы, а также статичный метод initial(), через который собственно и происходит инстанцирование нужного «подкласса» (Class1 и Class2). Абстрактный класс, в отличие от интерфейса, позволяет создать общую функциональность, что немного упрощает код в расширяющих его классах.
Абстрактный метод run() говорит о том, что этот метод должен быть реализован во всех фабриках.
При создании фабрики, нужно сразу указывать какой именно класс реализации будет использован.
$a = CommonAbstract::initial('Class1');
$a->run(); // Class1 run
$b = CommonAbstract::initial('Class2');
$b->run(); // Class2 run
Какой именно вариант, зависит от задач. Например так:
$type_file = 'zip'; // rar, arj
if ($type_file == 'zip') {
$f = CommonAbstract::initial('ZipClass');
} elseif ($type_file == 'rar') {
$f = CommonAbstract::initial('RarClass');
} else {
$f = CommonAbstract::initial('OtherClass');
}
$f->pack();
В абстрактной фабрике все «подклассы» были жестко заданы в каждой фабрике. Здесь же мы можем не меняя кода базового класса, просто добавить ещё один класс и подключить его через CommonAbstract::initial.
Существует ещё одна модификация Фабричного метода, которая отличается от этой способом инстанцирования. Здесь используется статичный метод, но можно сразу передать в CommonAbstract готовый класс. Тогда в методе initial инстанцирование уже не нужно.
$type_file = 'zip'; // rar, arj
if ($type_file == 'zip') {
$zip = new ZipClass();
$f = CommonAbstract::initial($zip);
} elseif ($type_file == 'rar') {
$f = CommonAbstract::initial(new RarClass()); // или так
} else {
$other= new OtherClass();
$f = CommonAbstract::initial($other);
}
$f->pack();
По сути это одно и тоже, только писать кода придется больше. :-)