flyweight Приспособленец (англ. Flyweight, “легковесный (элемент)”) — структурный шаблон проектирования, при котором объект, представляющий себя как уникальный экземпляр в разных местах программы, по факту не является таковым.

Сам шаблон очень прост. В прошлом примере, мы генерировали отчет. Как и любой документ, наш отчёт мы можем разбить на компоненты. Название, контент, подпись, печать и т.д. Как мы видим многие компоненты могут повторяться, а отличие их будет только в состоянии. Каждая инициализация нового объекта использует n ресурса. И рано или поздно мы можем достичь предела. Данный шаблон даёт нам возможность использовать повторно один и тот же компонент системы, лишь меняя его состояние.

  • Factory.php
                  
    <?php
    
    namespace DesignPatterns\Structural\Flyweight;
    
    use Countable;
    
    /**
     * Class Factory
     * @package DesignPatterns\Structural\Flyweight
     */
    class Factory implements Countable
    {
        /**
         * @var array
         */
        protected $pool = [];
    
        /**
         * @param string $name
         *
         * @return TitleFlyweightInterface
         */
        public function get(string $name): TitleFlyweightInterface
        {
            if (!isset($this->pool[$name])) {
                $this->pool[$name] = new Title($name);
            }
    
            return $this->pool[$name];
        }
    
        /**
         * @return int
         */
        public function count(): int
        {
            return count($this->pool);
        }
    }
    
                  
  • Title.php
                  
    <?php
    
    namespace DesignPatterns\Structural\Flyweight;
    
    /**
     * Class Title
     * @package DesignPatterns\Structural\Flyweight
     */
    class Title implements TitleFlyweightInterface
    {
        /**
         * @var string
         */
        protected $name;
    
        /**
         * Contract constructor.
         *
         * @param string $name
         */
        public function __construct(string $name)
        {
            $this->name = $name;
        }
    
        /**
         * @param string $color
         *
         * @return string
         */
        public function print(string $color): string
        {
            return sprintf('This is %s title with color %s.', $this->name, $color);
        }
    }
    
                  
  • TitleFlyweightInterface.php
                  
    <?php
    
    namespace DesignPatterns\Structural\Flyweight;
    
    /**
     * Interface TitleFlyweightInterface
     * @package DesignPatterns\Structural\Flyweight
     */
    interface TitleFlyweightInterface
    {
        /**
         * @param string $color
         *
         * @return string
         */
        public function print(string $color): string;
    }
    
                  
  • Test case:

    FactoryTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Structural\Flyweight;
    
    use DesignPatterns\Structural\Flyweight\Factory;
    use PHPUnit_Framework_TestCase;
    
    class FlyweightTest extends PHPUnit_Framework_TestCase
    {
        /**
         * @var Factory
         */
        protected static $factory;
    
        public static function setUpBeforeClass(): void
        {
            self::$factory = new Factory();
        }
    
        public function testCreateFirstTitle()
        {
            $firstTitle = self::$factory->get('first');
            $this->assertInstanceOf('DesignPatterns\Structural\Flyweight\TitleFlyweightInterface', $firstTitle);
        }
    
        public function testCreateSecondTitle()
        {
            $secondTitle = self::$factory->get('second');
            $this->assertInstanceOf('DesignPatterns\Structural\Flyweight\TitleFlyweightInterface', $secondTitle);
        }
    
        public function testSameFirstTitleObjects()
        {
            $firstTitle = self::$factory->get('first');
            $sameFirstTitle = self::$factory->get('first');
            $this->assertSame($firstTitle, $sameFirstTitle);
        }
    
        public function testSameSecondTitleObjects()
        {
            $secondTitle = self::$factory->get('second');
            $sameSecondTitle = self::$factory->get('second');
            $this->assertSame($secondTitle, $sameSecondTitle);
        }
    
        public function testPrint()
        {
            $firstTitle = self::$factory->get('first');
            $this->assertEquals('This is first title with color black.', $firstTitle->print('black'));
        }
    
        public function testFactoryCount()
        {
            $this->assertEquals(2, self::$factory->count());
        }
    }