Создание вещей может быть сложным, когда вы не можете предвидеть, какой тип объектов вам нужно создать или как их создать. Возьмем, к примеру, фабрику, которая производит большое количество продукции. Каждый продукт может состоять из любого количества компонентов в их инвентаре. Рабочие знают, что находится в инвентаре, но не обязательно заранее знают, какую продукцию они будут производить. Шаблон проектирования Factory Method может быть применен к аналогичным ситуациям в программировании, когда у вас есть набор классов компонентов, но вы не будете точно знать, какой из них вам потребуется создать до времени выполнения. В этой статье я покажу вам, как шаблон Factory Method можно использовать для создания различных объектов, не зная заранее, какого рода объекты ему нужно создать или как этот объект создается.
Фабричный метод
Шаблон Factory Method — это шаблон проектирования, используемый для определения интерфейса времени выполнения для создания объекта. Он называется фабрикой, потому что он создает различные типы объектов, не обязательно зная, какой тип объекта он создает или как его создать.
Вот пример того, как работает фабричный шаблон. Предположим, у вас есть класс ProductFactory
<?php
class ProductFactory
{
public static function build($type) {
// assumes the use of an autoloader
$product = "Product_" . $type;
if (class_exists($product)) {
return new $product();
}
else {
throw new Exception("Invalid product type given.");
}
}
}
Определив build()
<?php
// build a new Product_Computer type
$myComputer = ProductFactory::build("Computer");
// build a new Product_Tablet type
$myTablet = ProductFactory::build("Tablet");
Шаблон Factory Method обычно используется в следующих ситуациях:
- Класс не может предвидеть тип объектов, которые ему необходимо создать заранее.
- Класс требует, чтобы его подклассы указали объекты, которые он создает.
- Вы хотите локализовать логику для создания экземпляра сложного объекта.
Шаблон Factory Method полезен, когда вам необходимо абстрагировать создание объекта от его фактической реализации. Допустим, фабрика будет строить тип продукта «MobileDevice». Мобильное устройство может состоять из любого количества компонентов, некоторые из которых могут и будут меняться позже, в зависимости от технологических достижений.
<?php
class Product_MobileDevice
{
private $components;
public function __construct() {
// this device uses a 7" LCD
$this->addComponent(ProductFactory::build("LCD", 7));
// and features an 1GHz ARM processor
$this->addComponent(ProductFactory::build("CPU_ARM", 1));
}
...
}
// build a new Product_MobileDevice type
$myDevice = ProductFactory::build("MobileDevice");
$myDevice->use();
Логика для создания объекта Product_MobileDevice
Если позже вы захотите заменить 7-дюймовый ЖК-экран на 10-дюймовый сенсорный экран, вы можете внести изолированные изменения в класс MobileDevice, не затрагивая остальную часть вашего приложения.
Заводы, использующие другие заводы
Поскольку экземпляр объекта инкапсулирован, он также может использовать фабрики сам. Чтобы еще больше расширить идею создания абстрактных объектов, давайте воспользуемся аналогией, не связанной с разработкой программного обеспечения. Автомобильный завод производит автомобили определенной марки, модели и цвета, но он не может производить все необходимые детали, необходимые для сборки автомобиля. Другими словами, он делегирует производство этих деталей другим фабрикам, которые он затем использует для создания новых транспортных средств.
По этому сценарию автомобильный завод может выглядеть так:
<?php
class VehicleFactory
{
public static function build($make, $model, $color) {
$vehicle = new Vehicle;
// vehicle needs a chassis which is produced by another factory
$vehicle->addPart(VehicleChassisFactory::build($make, $model));
// needs an engine built by someone else
$vehicle->addPart(VehicleEngineFactory::build($make, $model));
// it needs a bodykit made by another factory
$vehicle->addPart(VehicleBodyFactory::build($make, $model, $color));
// and interiors are made by... you guessed it, someone else
$vehicle->addPart(VehicleInteriorFactory::build($make, $model, $color));
// ...add more parts
return $vehicle;
}
}
// build a new white VW Amarok
$myCar = VehicleFactory::build("Volkswagon", "Amarok", "white");
$myCar->drive();
Вуаля! Блестящая новая машина. Класс VehicleFactory
Резюме
В этой статье вы узнали, как шаблон Factory Method можно использовать для локализации построения различных объектов и для создания объектов, не зная заранее, какой тип вам нужен. Вы также видели, что фабричные методы могут использовать другие фабричные методы для создания объектов и определения объектов, которые они производят.
Изображение через yuminglin / Shutterstock