prototype Прототип (англ. Prototype) дозволяє створювати нові об’єкти на основі деякого об’єкта-прототипу при цьому зовсім необов’язково знати, як необхідний об’єкт влаштований.

Приклад, звичайно, не дуже, але він покаже суть шаблону. Перед подачею наші бургери потрібно скласти в коробки. Створення коробки звичним шляхом через new займає багато часу (у конструкторі ми емулюємо затримку в 1 секунду). Якщо потрібні 10 – це 10 секунд, 100 – 100 секунд і т.д. Що нам заважає зробити один спільний об’єкт, а далі його клонувати?

  • BoxPrototype.php
                  
    <?php
    
    namespace DesignPatterns\Creational\Prototype;
    
    /**
     * Class BoxPrototype
     * @package DesignPatterns\Creational\Prototype
     */
    class BoxPrototype
    {
        /**
         * @var string
         */
        protected $title;
    
        /**
         * BoxPrototype constructor.
         *
         * If TRUE === delay, init object created 1 sec.
         *
         * @param bool $delay
         */
        public function __construct($delay = false)
        {
            if (true === $delay) {
                sleep(1);
            }
        }
    
        /**
         * All classes have the magic method __clone.
         * Implement this method if you want to change the default behavior.
         */
        public function __clone()
        {
        }
    
        /**
         * @return string
         */
        public function getTitle(): string
        {
            return $this->title;
        }
    
        /**
         * @param string $title
         *
         * @return void
         */
        public function setTitle(string $title)
        {
            $this->title = $title;
        }
    }
    
                  
  • Test case:

    PrototypeTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Creational\Prototype;
    
    use DesignPatterns\Creational\Prototype\BoxPrototype;
    use PHPUnit_Framework_TestCase;
    
    class PrototypeTest extends PHPUnit_Framework_TestCase
    {
        public function testPerformanceGetBoxWithDelay()
        {
            $start = $this->getTime();
    
            for ($i = 0; $i < 15; $i++) {
                $box = new BoxPrototype(true);
                $box->setTitle('BOX#' . $i);
                $this->assertInstanceOf('DesignPatterns\Creational\Prototype\BoxPrototype', $box);
            }
    
            $finish = $this->getTime();
    
            return $finish - $start;
        }
    
        /**
         * @depends testPerformanceGetBoxWithDelay
         *
         * @param int $testPerformanceInitWithNew
         */
        public function testPerformanceGetBoxWithClone(int $testPerformanceInitWithNew)
        {
            $start = $this->getTime();
    
            $boxPrototype = new BoxPrototype(true);
    
            for ($i = 0; $i < 15; $i++) {
                $box = clone $boxPrototype;
                $box->setTitle('BOX#' . $i);
                $this->assertInstanceOf('DesignPatterns\Creational\Prototype\BoxPrototype', $box);
            }
    
            $finish = $this->getTime();
    
            $testPerformanceInitWithClone = $finish - $start;
    
            $this->assertGreaterThan($testPerformanceInitWithClone, $testPerformanceInitWithNew);
        }
    
        private function getTime()
        {
            return (int)microtime(true);
        }
    }