НЕ МОЛЧИ!!!    Сделай что-нибудь, чтобы остановить войну России в Украине.
Иначе завтра ТЫ будешь следующим!

Пример использования шаблона Aбстрактная фабрика

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

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

Пример использования шаблона Абстрактная фабрика

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



 

Замечу, сервер не догадывается, какую тему захочет выбрать пользователь. Набор элементов один и тот же, различие только в деталях отрисовки — просится типовая обработка запроса. Вот здесь то и будет удобен паттерн Абстрактная фабрика.

Вначале создаем иерархию фабрик.

<?php

abstract class Factory
{
  abstract public function createLabel();
  
  abstract public function createButton();
}

class FactoryLight extends Factory
{
  public function createLabel()
  {
    return new LabelLight();
  }
  
  public function createButton()
  {
    return new ButtonLight();
  }
}

class FactoryDark extends Factory
{
  public function createLabel()
  {
    return new LabelDark();
  }
  
  public function createButton()
  {
    return new ButtonDark();
  }
}

Теперь создаем иерархию продуктов.

<?php

abstract class Label
{
  protected $caption = 'Label';
   
  public function getCaption()
  {
      return $this->caption;
  }
  
  public function setCaption($str)
  {
      $this->caption = $str;
  }

  abstract public function render();
}

class LabelLight extends Label
{
    public function render()
    {
        $str = '<label>';
        $str .= $this->caption;
        $str .= '</label>';
        return $str;
    }
}

class LabelDark extends Label
{
  public function render()
  {
        $str = '<label>';
        $str .= $this->caption;
        $str .= '</label>';
        return $str;
  }
}

abstract class Button
{
  protected $value = 'Button';
  
  public function getValue()
  {
     return $this->value;
  }
  
  public function setValue($str)
  {
      $this->value = $str;
  }
  
  abstract function render();
}

class ButtonLight extends Button
{
  function render()
  {
      $str = '<input type="button" ';
      $str .= "value=\"$this->value\">";
      return $str;
  }
}

class ButtonDark extends Button
{
  function render()
  {
      $str = '<input type="button" ';
      $str .= "value=\"$this->value\">";
      return $str;
  }  
}

Классы шаблона созданы, теперь пишем обработчик запроса.

<?php

require 'Elements.php';
require 'AbstFactory.php';

$theme = $_GET["theme"];
$factory = getFactory($theme);

$response = getResponse($factory, $theme);
echo $response;


function getFactory($theme)
{
  switch ($theme) {
    case 'light' :
      $factoryElem = new FactoryLight();
    break;
    case 'dark' :
      $factoryElem = new FactoryDark();
      break;
  }
  return $factoryElem;
}

function getResponse($factory, $theme)
{
  $themeName = ucfirst($theme);
  $label = $factory->createLabel();
  $label->setCaption('Текст метки');
  $button = $factory->createButton();
  $button->setValue('Отправить');
  $response = include 'table.php';
  return $response;
}

Выводы

Подведем итоги. Да, над созданием классов фабрик и семейств продуктов пришлось потрудиться, зато в обработчике запроса код простой и не зависит от типа создаваемого объекта. Более того, если понадобится еще одна тема, доработка обработчика запроса будет минимальной, а значит и вероятность внесения ошибок в приложение в результате правок также будет минимальной.

Исходные коды примера вы можете скачать по этой ссылке. Для его работы нужны лишь Web сервер и PHP.