Шаблон проектирования: Фабрика
Фабричный метод, фабрика или виртуальный конструктор – это все шаблон проектирования, который предоставляет интерфейс для создания объектов имеющих схожие свойства своим подклассам.
Грубо говоря, фабричный метод – это обычный метод класса, который возвращает объекты при обращении к нему (создавая их при этом). Такой прием, в основном, используется для унификации архитектуры системы. Как следствие этого – объекты, порожденные фабричным методом, имеют одинаковые интерфейсы.
На практике это выглядит так:
… $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() { ... } } ?>
Буду рад, если кто-нибудь поделится опытом и расскажет, в каких ситуациях этот шаблон применял. А мне добавить тут особо и нечего. Поэтому все
Удачи.
Гораздо интереснее было бы, если бы вы привели пример класса-фабрики, который может создавать объекты не только по списку, а произвольные.
Да и в общем, не вижу в этом шаблоне особого смысла, почему не использовать интерфейсы если так уже надо унифицировать классы?
> Гораздо интереснее было бы, если бы вы привели пример класса-фабрики, который может создавать объекты не только по списку, а произвольные.
Не совсем понял - что значит произвольные? Преобразовать параметр, переданный фабричному методу в инициализацию какого-класса можно разными способами. Но если классы будут разными, то и инициализировать их нужно будет по-разному - это ограничивает как бы область применения (нельзя поэтому совсем уж разные классы порождать через это дело).
> Да и в общем, не вижу в этом шаблоне особого смысла, почему не использовать интерфейсы если так уже надо унифицировать классы?
В примере с машинами, унификация классов - это скорее следствие унификации способа порождения объектов. Т.е. основное назначение шаблона фабричный метод - унификация способа порождения схожих объектов. Пример можно глянуть в классе Zend_DB фреймворка Zend - там этот прием используется для генерации разных адаптеров для БД.
И всё таки. Как избавиться от жёстко заданного списка классов.
Например, если я в будущем захочу приинклудить класс Mersedes, но чтобы не изменять код CarsFactory
Думаю, гораздо более абстрактно будет использовать, пардон, абстрактную фабрику:
class CarsFactory {
function createCar($brand) {
$car_obj = null;
$brand = ucfirst(strtolower($brand));
if(class_exists($brand))
$car_obj = new $brand;
return $car_obj;
}
}
Это частично решит и проблему “жестко заданных классов”
В kohana-фреймворке factory-паттерн используется повсюду: $this->content = View::factory(‘layoutes/index’)->set(‘title’, ‘Test title’);
$cars = ORM::factory(‘car’)->find_all();
Для chain-вызова методов в основном, красиво получается в итоге
Делал почти так же, только без 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(); //Выводим текст из нашего второго объекта
?>
szc
dc
sdc
sdc
sd
cs