НЕ МОЛЧИ!!!    Сделай что-нибудь, чтобы остановить войну России в Украине.
...бойтесь людей равнодушных - именно с их молчаливого согласия происходят все самые ужасные преступления на свете.   ("Репортаж с петлёй на шее")

Пример использования шаблона Фабричный метод

Действующий пример использования в приложении шаблона проектирования Фабричный метод.

Фабричный метод — это порождающий шаблон проектирования, его описание было приведено в предыдущей записи. Описание паттерна встречается достаточно часто, чего не скажешь по поводу примеров использования фабричного метода в приложении. Попробуем как-то восполнить этот пробел.

Пусть у нас есть приложение, где нам надо «работать» с набором товаров, давайте будем продавать автомобили. Чтобы продать, надо, как минимум, показать, какой товар есть в наличии. Вот этим мы и займемся. Пользователь выбирает производителя и получает список доступных моделей выбранного бренда. Нас интересует наш шаблон проектирования, поэтому клиентскую часть оставим за кадром, тем более, там все просто — выбираем производителя и отправляем асинхронный запрос. Итак, пробуем.

Хочу обратить внимание. Сервер не знает, список продукции какого производителя будет запрошен, хотя напрашивается типовая обработка запроса по любому производителю. Вот как это производится на сервере с использованием шаблона Фабричный метод.
Создаем семейство классов конкретных производителей авто, в абстрактном классе Product определяем их интерфейс.

<?php

abstract class Product
{
  protected $brand = NULL;
  
  public function getBrandName()
  {
    return $this->brand; 
  }

  abstract public function getModels();
}

class BmvCar extends Product
{
  protected $brand = 'BMV';

  public function getModels()
  {
    return ["X1", "X2","X3","X4",];
  }
}

class RenoCar extends Product
{
  protected $brand = 'RENO';
  
  public function getModels()
  {
    return ["Clio", "Duster", "Scenic","Megan",];
  }  
}

Аналогичным образом, через наследование абстрактного класса, создаем классы фабрик, которые будут возвращать экземпляры конкретных производителей машин. В абстрактном классе Factory декларируется фабричный метод factoryMethod(), возвращающий экземпляр продукта. В наследниках Factory этот метод возвращает объект конкретного продукта.

<?php

abstract class Factory
{
  abstract public function factoryMethod();
}

class FactoryBmv extends Factory
{
  public function factoryMethod()	
  { 
    return new BmvCar();
  }
}

class FactoryReno extends Factory
{
  public function factoryMethod()	
  { 
    return new RenoCar();
  }
}

Теперь осталось привести код обработки клиентского запроса, который использует созданные классы.

<?php

require 'Product.php';
require 'Factory.php';

$brands = ["bmv" => new FactoryBmv(), "reno" => new FactoryReno(),];

$brandId = mb_strtolower($_GET["brand"]);
$factory = $brands[$brandId];
if (is_null($factory)) {
  $factory = $brands["bmv"];
}
$brand = $factory->factoryMethod();
$models = $brand->getModels();

$options = '';
foreach($models as $model) {
  $options .= '<option>' .$model .'</option>';
}

$response = 'Производитель ' .'<b>'.$brand->getBrandName().'</b>';
$response .= '<ul>Список доступных моделей:';
$response .= $options;
$response .= '</ul>';
echo $response;

Что имеем в итоге – код приложения мало зависит от выбранного производителя, такой код достаточно просто корректировать при изменении исходных данных. Например, при расширении списка производителей, нам потребуется создать классы производителя и его «фабрики», а в обработчике запроса массив $brands со списком брендов дополнить новым элементом. Даже при полной замене авто на велосипеды потребуется заменить иерархии классов, зато в обработчике запроса изменения будут минимальными.

Вернуться к списку шаблонов проектирования можно это по ссылке.