Прототип (англ. 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);
}
}