Purpose
The purpose of the design pattern
To avoid the cost of creating objects the standard way (new Foo()) and instead create a prototype and clone it.
Examples
Examples of how the design pattern can be used
Large amounts of data (e.g. create 1,000,000 rows in a database at once via a ORM).
UML
UML design pattern diagram
Code
Code snippets
BookPrototype
Abstract BookPrototype class that concrete subclasses (FooBookPrototype and BarBookPrototype) extend. This exists to eliminate boilerplate code (duplicate) over the concrete subclasses.
namespace DesignPatterns\Creational\Prototype;
abstract class BookPrototype
{
protected string $title;
protected string $category;
abstract public function __clone();
final public function getTitle(): string
{
return $this->title;
}
final public function setTitle(string $title): void
{
$this->title = $title;
}
}
FooBookPrototype
FooBookPrototype is a concrete subclass which extends BookPrototype.
namespace DesignPatterns\Creational\Prototype;
class FooBookPrototype extends BookPrototype
{
protected string $category = 'Foo';
public function __clone()
{
}
}
BarBookPrototype
BarBookPrototype is a concrete subclass which extends BookPrototype.
namespace DesignPatterns\Creational\Prototype;
class BarBookPrototype extends BookPrototype
{
protected string $category = 'Bar';
public function __clone()
{
}
}
Tests
If we’re executing code which is quite expensive, we can avoid the cost of creating objects the typical way by cloning them.
In the example below we’re looping through and cloning a prototype, then adjusting the title via the setTitle method.
In the example below we’re looping through and cloning a prototype, then adjusting the title via the setTitle method.
public function testCanGetFooBook()
{
$fooPrototype = new FooBookPrototype();
$barPrototype = new BarBookPrototype();
for ($i = 0; $i < 10; $i++) {
$book = clone $fooPrototype;
$book->setTitle('Foo Book No ' . $i);
$this->assertInstanceOf(FooBookPrototype::class, $book);
}
for ($i = 0; $i < 5; $i++) {
$book = clone $barPrototype;
$book->setTitle('Bar Book No ' . $i);
$this->assertInstanceOf(BarBookPrototype::class, $book);
}
}