multiton Пул одиночек (англ. Multiton) - похож на шаблон Одиночка. Позволяет создавать и содержать несколько одиночек, доступ к которым можно получить по уникальному “ключу”.

Продолжаем тему нашей закусочной. Бизнес идёт в гору, и мы устанавливаем ещё пару кассовых аппаратов. Для удобного доступа ко всем аппаратам мы создадим систему ShopCashSystem, которую и реализует наш Multiton. Как и с Singleton‘ом, мы закрыли все магические методы. Для доступа к объекту используется статический метод ShopCashSystem::getInstance().

Применение:

  • Два объекта для доступа к базам данных, к примеру, один для MySQL, а второй для SQLite
  • Несколько логирующих объектов (один для отладочных сообщений, другой для ошибок и т.п.)

Примечание: Иногда этот шаблон называют Реестр одиночек. Напомню про антипаттерн Одиночество (Singletonitis).

  • MultitonInterface.php
                  
    <?php
    
    namespace DesignPatterns\Creational\Multiton;
    
    /**
     * Interface MultitonInterface
     * @package DesignPatterns\Creational\Multiton
     */
    interface MultitonInterface
    {
        /**
         * @param string $instanceName
         *
         * @return MultitonInterface
         */
        public static function getInstance(string $instanceName): self;
    }
    
                  
  • ShopCashSystem.php
                  
    <?php
    
    namespace DesignPatterns\Creational\Multiton;
    
    use DesignPatterns\Creational\Singleton\CashboxTrait;
    
    /**
     * Class ShopCashSystem
     * @package DesignPatterns\Creational\Multiton
     */
    class ShopCashSystem implements MultitonInterface
    {
        use CashboxTrait;
    
        /**
         * @var MultitonInterface[]
         */
        private static $instances = [];
    
        /**
         * Return Singleton instance
         *
         * @param string $instanceName
         *
         * @return MultitonInterface
         */
        public static function getInstance(string $instanceName): MultitonInterface
        {
            if (!isset(self::$instances[$instanceName])) {
                self::$instances[$instanceName] = new self();
            }
    
            return self::$instances[$instanceName];
        }
    
        private function __construct()
        {
        }
    
        private function __clone()
        {
        }
    
        private function __wakeup()
        {
        }
    }
    
                  
  • Test case:

    MultitonTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Creational\Multiton;
    
    use DesignPatterns\Creational\Multiton\ShopCashSystem;
    use PHPUnit_Framework_TestCase;
    
    class MultitonTest extends PHPUnit_Framework_TestCase
    {
        public function testUniqueness()
        {
            $firstCashbox = ShopCashSystem::getInstance('Cashbox#1');
            $secondCashbox = ShopCashSystem::getInstance('Cashbox#2');
    
            $this->assertInstanceOf('DesignPatterns\Creational\Multiton\MultitonInterface', $firstCashbox);
            $this->assertInstanceOf('DesignPatterns\Creational\Multiton\MultitonInterface', $secondCashbox);
    
            $this->assertNotSame($firstCashbox, $secondCashbox);
    
            $thirdCashbox = ShopCashSystem::getInstance('Cashbox#1');
    
            $this->assertSame($firstCashbox, $thirdCashbox);
    
            $firstCashbox->setCash(5);
    
            $this->assertSame($firstCashbox, $thirdCashbox);
        }
    }