Registry Singleton одиночка Как создать свой сайт > Вебмастеру > Создание своего сайта > Использование паттерна Registry

Использование паттерна Registry как альтернативы одиночкам (Singleton)

Когда живёшь чересчур долго,
в конце концов не остаётся даже знакомых…
«Корни неба», Роман Гари.



Основная идея

Паттерн Singleton (одиночка или синглтон) используют в нескольких случаях:

  • когда требуется, чтобы существовал только 1 объект какого-либо класса,
  • в случае, если инициализация объекта требует много ресурсов,
  • если объект используется во многих местах, а передавать его в качестве параметров методов проблематично.

    Это достаточно простой паттерн, поэтому во многих проектах он используется «на полную катушку». Однако, необходимо помнить, что Singleton свойственны все недостатки, присущие статическим методам — по причине явного указания имени класса одиночки тестирование затрудняется, а развивать проект становится труднее. Поэтому используйте Singleton только там, где действительно требуется создание одного и только одного экземпляра объекта. Во многих случаях использование Singleton можно избежать, если внедрить в проект паттерн Registry (реестр).

Проблема с использованием Singleton

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

<?php
class A 
{
  function method1() {
    $b = B :: instance();
    $b->doSomething();
  }
}
 
class B 
{
  function instance(){...}
 
  function doSomething() {
    // method implementation
  }
}
?>

    Это типичная ситуация, которая характерна для большого количества проектов. Есть класс А, который использует методы класса B, являющегося одиночкой. В этом случае мы имеем зависимость класса А от класса B, а не от какого-либо интерфейса. При тестировании класса А нам придётся создавать фикстуру, которая будет обеспечивать правильную инициализацию класса В, поэтому тест будет бОльшим по размеру, сложнее, более хрупким и т. д. Не будем развивать эту мысль, так как она была уже очень хорошо описана ранее.

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

    Итак, основная проблема с Singleton — это явное указание класса одиночки в коде. Так как мы не можем изменить эту зависимость, значит нужно иметь возможность подменять реализацию интерфейса одиночки. То есть Singleton нужно использовать для делегирования выполнения методов другим объектам. То есть гораздо лучше будет сделать так:

<?php
class A 
{
  function method1(){
    $b = B :: instance();
    $b->doSomething();
  }
}
 
interface Server
{
  function doSomething();
}
 
class B implements Server
{
  private $server;
 
  function instance(){...}
  function doSomething(){
    $this->server->doSomething();
  }
 
  function setServer($server){
    $this->server = $server;
  }
}
 
class C implements Server
{
  function doSomething() {
    // method implementation
  }
}
?>

    Теперь можно передать в одиночку B объект другого класса в качестве $server. То есть мы будем иметь возможность расширить поведение класса A, в случае необходимости. Плюс теперь тест не обязан знать детали реализации интерфейса Server.

<?php
Mock :: generate('Server');
 
class ClassATest extends UnitTestCase
{
  private $mock_server;
 
  function setUp() {
    $this->mock_server = new MockServer($this);
 
    $this->_fixtureForClassA();
  }
 
  function tearDown() {
    $this->mock_server->tally();
  }
 
  function test1(){
    $b = B :: intance();
    $b->setServer($this->mock_server);
    $this->mock_server->expectOnce('doSomething');
    $this->mock_server->setReturnValue('doSomething', $for_result1);
 
    $a = new A();
    $this->assert($a->method1(), $result1);
  }
}
?>

    Данный способ хорошо зарекомендовал себя в случае, когда одиночек мало, а их интерфейсы не слишком раздуты. Как аналог можно предложить добавление в Singleton метода setInstance($new_instance). Этим приёмом очень часто пользуются при рефакторинге legacy систем, которые напичканы одиночками.

Использование паттерна Registry

Паттерн Registry является прекрасной альтернативной использованию Singleton. Registy может заменить целый набор одиночек в случаях, когда внедрение одиночек было связано именно с экономией на инициализации объекта, а также в том случае, если одиночкой был просто «популярный» объект.

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

<?php
class AnyRegistry extends Registry
{
  private $_some_object;
 
  function getSomeObject()
  {
    if($this->_some_object)
      return $this->_some_object;
 
    $this->_some_object = new SomeObject();
 
    return $this->_some_object;
  }
}
?>

    Даже если требование по наличию только одного экземпляра какого-либо класса класса сохраняется, то конструктор такого класса можно закрыть и продолжать использовать Singleton. Но в целях облегчения тестирования, клиенты, всё же, должны получать этот экземпляр только через Registry.

Автор: Вики.Агилдев.Ру.

Комментарии:


⇓ 

Поделись ссылкой на Seoded.ru с друзьями, знакомыми и собеседниками в соцсетях и на форумах! А сам сайт добавь в закладки! Так победим.

Поделиться ссылкой на эту страницу в:

Полезные ссылки:

Копирайтер-одиночка в Интернете зарабатывает, как целая команда На Форексе почти все — одиночки

Ещё материалы по этой теме:

Статические вызовы Прощай Smarty Графическое меню на CSS Позиционирование в CSS Наследование классов в Internet Explorer
основан в 2008 г. © Все права на материалы сайта Seoded.ru принадлежат Алексею Вострову.
Копирование (полное или частичное) любых материалов сайта возможно только с разрешения автора и при указании ссылки на источник.
Ослушавшихся находит и забирает Бабайка!