Шаблон проектирования: Фабрика
Фабричный метод, фабрика или виртуальный конструктор – это все шаблон проектирования, который предоставляет интерфейс для создания объектов имеющих схожие свойства своим подклассам.
Грубо говоря, фабричный метод – это обычный метод класса, который возвращает объекты при обращении к нему (создавая их при этом). Такой прием, в основном, используется для унификации архитектуры системы. Как следствие этого – объекты, порожденные фабричным методом, имеют одинаковые интерфейсы.
На практике это выглядит так:
…
$carsFactory = new CarsFactory;
$cars['toyota'] = $carsFactory->createCar('toyota');
$cars['bmw'] = $carsFactory->createCar('bmw');
foreach ($cars as $mod => $obj) {
echo 'Max speed: '.$obj->getMaxSpeed().'';
echo 'Weight: '.$obj->getWeight();
}
…
Реализуется такой механизм довольно просто:
<?php
class CarsFactory {
function createCar($brand) {
$car_obj = 0;
switch ($brand) {
case 'toyota': $car_obj = new Toyota;
case 'bmw': $car_obj = new Bmw;
default: $car_obj = new Toyota;
}
return $car_obj;
}
}
abstract class Car {
abstract function getMaxSpeed();
abstract function getWeight();
}
class Toyota extends Car {
...
public function getMaxSpeed() {
...
}
}
?>
Буду рад, если кто-нибудь поделится опытом и расскажет, в каких ситуациях этот шаблон применял. А мне добавить тут особо и нечего. Поэтому все
Удачи.




Декабрь 20th, 2008
Гораздо интереснее было бы, если бы вы привели пример класса-фабрики, который может создавать объекты не только по списку, а произвольные.
Да и в общем, не вижу в этом шаблоне особого смысла, почему не использовать интерфейсы если так уже надо унифицировать классы?
Декабрь 21st, 2008
> Гораздо интереснее было бы, если бы вы привели пример класса-фабрики, который может создавать объекты не только по списку, а произвольные.
Не совсем понял – что значит произвольные? Преобразовать параметр, переданный фабричному методу в инициализацию какого-класса можно разными способами. Но если классы будут разными, то и инициализировать их нужно будет по-разному – это ограничивает как бы область применения (нельзя поэтому совсем уж разные классы порождать через это дело).
> Да и в общем, не вижу в этом шаблоне особого смысла, почему не использовать интерфейсы если так уже надо унифицировать классы?
В примере с машинами, унификация классов – это скорее следствие унификации способа порождения объектов. Т.е. основное назначение шаблона фабричный метод – унификация способа порождения схожих объектов. Пример можно глянуть в классе Zend_DB фреймворка Zend – там этот прием используется для генерации разных адаптеров для БД.
Август 7th, 2009
И всё таки. Как избавиться от жёстко заданного списка классов.
Например, если я в будущем захочу приинклудить класс Mersedes, но чтобы не изменять код CarsFactory
Сентябрь 16th, 2009
Думаю, гораздо более абстрактно будет использовать, пардон, абстрактную фабрику:
class CarsFactory {
function createCar($brand) {
$car_obj = null;
$brand = ucfirst(strtolower($brand));
if(class_exists($brand))
$car_obj = new $brand;
return $car_obj;
}
}
Это частично решит и проблему “жестко заданных классов”
Октябрь 12th, 2009
В kohana-фреймворке factory-паттерн используется повсюду: $this->content = View::factory(‘layoutes/index’)->set(‘title’, ‘Test title’);
$cars = ORM::factory(‘car’)->find_all();
Для chain-вызова методов в основном, красиво получается в итоге
Декабрь 4th, 2009
Делал почти так же, только без SWIТCH. Решил немного изменить свою версию и наконец-то разместить на своём блоге, вот что получилось:
text = $name; //присваиваем переменной $text класса значение параметра $name
}
public function myGetText()
{
return $this->text; //Возвращаем переменную $text
}
}
class MyClass2 extends ABSTR //Наш второй класс
{
public function myGetText()
{
return “MyClass2″; //возвращаем текст
}
}
$Factory = new Factory; //Создаём наш объект
$arr_obj = array(); //Массив в котором будут храниться наши объекты
$arr_obj['mc1'] = $Factory->create(‘MyClass1′, ‘Text’); //засовываем в элемента `mc1` массива $arr_obj новый объект (MyClass1) с параметром `Text`
$arr_obj['mc2'] = $Factory->create(‘MyClass2′); //засовываем в элемента `mc2` массива $arr_obj новый объект (MyClass2) без параметра
echo $arr_obj['mc1']->myGetText(); //Выводим текст из нашего первого объекта
echo “”;
echo $arr_obj['mc2']->myGetText(); //Выводим текст из нашего второго объекта
?>