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