• Шаблоны проектирования: руководство для начинающих. Часть вторая

    by  • 20.08.2010 • OOP, php, программирование • 1 Комментарий

    design patterns2 150x150 Шаблоны проектирования: руководство для начинающих. Часть вторая

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

    Шаблона проектирования Фабрика

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

    Основная цель этого паттерна — это создание разных классов в одном методе. Исходя из контекста, переданного в метод Фабрики, мы можем возвращать нужный объект.

    Когда лучше использовать?

    Использовать его следует тогда, когда нужно создать множество разных сущностей. Скажем, у вас есть класс кнопки, этот класс может иметь несколько реализация, таких как графическая кнопка или кнопка в форме в качестве submit’а. В зависимости от места, вам может понадобится создание разных кнопок — вот тут и придет на помощь паттерн Фабрика.

    Давайте создадим наши классы:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?php
    abstract class Button
    {
       protected $_html;
       
       public function getHtml()
       {
          return $this->_html;
       } 
    }

    class ImageButton extends Button
    {
       protected $_html = 'html для графический кнопки';
    }

    class InputButton extends Button
    {
       protected $_html = 'html для сабмит кнопки';
    }
    ?>

    Сейчас же создадим наш класс Фабрика:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <?php
    class ButtonFactory
    {
       public function createButton($type)
       {
          $baseClass = 'Button';
          $targetClass = ucfirst($type) . $baseClass;
         
          if (class_exists($targetClass) and
             is_subclass_of($targetClass, $baseClass)) {
             return $targetClass;
          } else {
             throw new Exception($type . ' кнопка не найдена');
          }
       }
    }
    ?>

    Использовать код можно примерно так:

    1
    2
    3
    4
    5
    6
    <?php
       $buttons = array('image', 'input');
       foreach($buttons as $button) {
          echo ButtonFactory::createButton($button)->getHtml();
       }
    ?>

    Данный кусок кода должен вывести HTML всех кнопок, имеющихся у нас. Таким образом, мы имеем возможность определить какую кнопку нас создать, в зависимости от ситуации.

    Шаблон проектирования Декоратор

    Паттерн Декоратор — структурный шаблон который добавляет дополнительный функционал объекту в режиме выполнения.

    Целью данного паттерна является добавление расширенного функционала к экземпляру, но в то же время оставить возможность инстанцировать объект без дополнительных возможностей. Также этот шаблон позволяет добавить множество декораторов к одному экземпляру. Этот паттерн являет собой своего рода альтернативу подклассам, которые наследуют функциональность родительского класса. В отличие от тех же подклассов, которые добавляют функицонал на режиме компиляии, Декоратор позволяет добавлять новый функционал в режиме выполнения, в нужных для этого ситуациях.

    Для реализации данного паттерна следует выполнить следующие действия:

    1. Подкласс оригинального класса поместить в класс декоратора.
    2. В класс декоратора добавить указатель.
    3. В конструктор класса декоратора передать указатель для инициализации объекта.
    4. Перенаправить все вызовы исходного класса указателю на данный класс
    5. В классе декоратора изменить все методы, чей функционал мы хотим изменить.
    Когда использовать?

    Лучшее место, чтобы использовать паттерн Декоратор там, где некоторым сущностям нужно иметь дополнительный функционал, только там, где это нужно. К примеру, у нас есть элемент HTML ссылка, ссылка для логаута (logout), которые должны выполнять разные вещи на одной странице. Для этого нам понадобится шаблон проектирования Декоратор.

    Сперва, давайте уясним какие «декорации» нам нужны.

    • Если мы на главной странице и осуществили вход на сайт, обернем ее тэгами h2
    • Если мы не на главной странице и также вошли на сайт, то просто подчеркнем ссылку
    • Если мы просто вошли на сайт, то обернуть ссылку <strong>

    Когда мы уяснили весь функционал, можем приступить к написанию кода.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    <?php
     class HtmlLinks
     {
       // методы, которые доступны всем ссылкам
     }
     
     class LogoutLink extends HtmlLinks
     {
       protected $_html;
       
       public function __construct()
       {
          $this->_html = '<a href="logout.php">Выйти</a>';
       }
       
       public function setHtml($html)
       {
          $this->_html = $html;
       }
       
       public function render()
       {
          echo $this->_html;
       }
     }
     
     class LogoutLinkH2Decorator extends HtmlLinks
     {
       protected $_logoutLink;
       
       public function __construct($logoutLink)
       {
          $this->_logoutLink = $logoutLink;
          $this->setHtml('<h2>' . $this->_html . '</h2>');
       }
       
       public function _call($name, $args)
       {
          $this->_logoutLink->$name($args[0]);
       }
     }
     
     class LogoutLinkUnderlineDecorator extends HtmlLinks
     {
       protected $_logoutLink;
       
       public function __construct($logoutLink)
       {
          $this->_logoutLink = $logoutLink;
          $this->setHtml('<u>' . $this->_html . '</u>');
       }
       
       public function __call($name, $args)
       {
          $this->_logoutLink->$name($args[0]);
       }
     }
    ?>

    Теперь давайте попробуем на деле Декоратор.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?php
    $logouLink = new LogoutLink();

    if ($isLoggedIn) {
       $logouLink = new LogoutLinkStrongDecorator($logouLink);
    }

    if ($inHomePage) {
       $logoutLink = new LogoutLinkH2Decorator($logouLink);
    } else {
       $logoutLink = new LogoutLinkUnderlineDecorator($logouLink);
    }
    $logoutLink->render();
    ?>

    Как видно на примере, мы можем объединять несколько декораторо, если у нас есть на то необходимость. Посколько все декораторы используют магическую функцию __call, мы можем вызвать оригинальный метод. Предположим, что мы сейчас находимся на главной странице и вошли на сайт, вывод должен быть таким:

    1
    <strong><h2><a href="logout.php">Выйти</a></h2></strong>

    Шаблон Синглтон

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

    Когда использовать?

    Если вам нужно передать данные из одного класса в другой, то вы можете использовать Синглтон в обход традиционной передачи с помощью конструктора или аргументов. Представьте вы создали класс для работы с сессиями, который имитирует $_SESSION суперглобального массива. Этот класс должен быть инстанцирован только один раз, мы можем реализовать это примерно так:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <?php
    class Session
    {
       private static $instance;
       
       public static function getInstance()
       {
          if (is_null(self::$instance)) {
             self::$instance = new self();
          }
          return self::$instance;
       }
       
       private function __construct() {}
       
       private function __clone() {}
       
       // другие методы, которые нужны нам для манипуляции с сессиями
    }
    // так мы можем получить единственный экземпляр данного класса
    $session = Session::getInstance();
    ?>

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

    Заключение

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

    Комментарии к "Шаблоны проектирования: руководство для начинающих. Часть вторая"

    1. 26.09.2010 at 14:13

      У вас в шаблоне Фабрики 2 ошибки:
      1. Метод createButton($type) должен быть static
      2. В этом же методе вы возвращаете просто название класса, а должны вернуть объект.
      У вас return $targetClass;
      а должно быть return new $targetClass;

    Добавить комментарий

    Ваш e-mail не будет опубликован. Обязательные поля помечены *