08.08 2010

Abstract factory

Перед прочтением ознакомьтесь с введением в паттерны проектирования на PHP, в котором описаны принятые соглашения и понятия. Данная статья дополняется с некоторой периодичностью, так что если вы ее читали ранее, не факт что данные не изменились.

AbstractFactory относиться к классу порождающих паттернов. Его основное назначение - предоставить интерфейс для создания семейства взаимосвязанных объектов, не специфицируя их классы.

Пример

Предположим, мы создаем некоторую игру-стратегию. Как и в каждой стратегии, здесь будут присутствовать несколько враждующих фракций. Например это будут пришельцы (Alien) и зомби (Zombie). Каждая из "рас", допустим, представлена пехотинцами (footman), транспортом (transport) и боевой техникой (weaponry). Для каждого юнита объявим класс.

class AlienFootman(){...}
class AlienTransport(){...}
class AlienWeaponry(){...}
class ZombieFootman(){...}
class ZombieTransport(){...}
class ZombieWeaponry(){...}

Тогда бой будет напоминать нечто подобное

$footman_1 = new AlienFootman();
$footman_2 = new ZombieFootman();
// и так для каждого юнита
$footman_1 -> attack($footman_2);

В целом неплохо, НО нам пришлось явно использовать имена классов в коде, и пока юнитов всего 3, это не страшно. А если их станет 200 разновидностей для каждой расы? А если добавиться еще 20 рас? То для определения одного пехотинца придется делать цепочку if else (switch) из 4000 ветвлений, что никак не правильно. В таких случаях применяют паттерн "Абстрактная фабрика".

Суть паттерна

UML

Суть абстрактной фабрики заключается в том, чтобы брать обязанность инстанации объекта на себя. Для каждого из семейств объектов (в нашем случае рас), создается конкретная фабрика (наследник абстрактной), посредством которой создаются продукты (в нашем случае юниты) этого семейства. Декларацию классов я выложил отдельным файлом, так как он довольно объемный.

$factory_1 = new ZombieFactory();
$factory_2 = new AlienFactory();

// Так как оба пехотинца имеют общий интерфейс, то нам неважно какому классу они принадлежат.
$footman_1 = $factory_1 -> createFootman();
$footman_2 = $factory_2 -> createFootman();
// Мы можем обращаться к ним одинаково

Теперь, если мы захотим изменить класс пехотинца на другой, то нам нужно будет его изменить только в фабричном методе

Где используется?

Этот паттерн используется в Zend Framework 2 в компоненте ServiceManager.

comments powered by Disqus