Прототип — это порождающий паттерн проектирования, который позволяет копировать объекты, не вдаваясь в подробности их реализации.
У вас есть объект, который нужно скопировать. Как это сделать? Нужно создать пустой объект такого же класса, а затем поочерёдно скопировать значения всех полей из старого объекта в новый.
Прекрасно! Но есть нюанс. Не каждый объект удастся скопировать таким образом, ведь часть его состояния может быть приватной, а значит — недоступной для остального кода программы.
Но есть и другая проблема. Копирующий код станет зависим от классов копируемых объектов. Ведь, чтобы перебрать все поля объекта, нужно привязаться к его классу. Из-за этого вы не сможете копировать объекты, зная только их интерфейсы, а не конкретные классы.
Паттерн Прототип поручает создание копий самим копируемым объектам. Он вводит общий интерфейс для всех объектов, поддерживающих клонирование. Это позволяет копировать объекты, не привязываясь к их конкретным классам. Обычно такой интерфейс имеет всего один метод clone.
Реализация этого метода в разных классах очень схожа. Метод создаёт новый объект текущего класса и копирует в него значения всех полей собственного объекта. Так получится скопировать даже приватные поля, так как большинство языков программирования разрешает доступ к приватным полям любого объекта текущего класса.
Объект, который копируют, называется прототипом (откуда и название паттерна). Когда объекты программы содержат сотни полей и тысячи возможных конфигураций, прототипы могут служить своеобразной альтернативой созданию подклассов.
В этом случае все возможные прототипы заготавливаются и настраиваются на этапе инициализации программы. Потом, когда программе нужен новый объект, она создаёт копию из приготовленного прототипа.
interface IPost { public function __clone(); } class Post implements IPost { private $title, $text; private $user; private $comment = []; private $created_at; public function __construct(User $user, $title, $text) { $this->user = $user; $this->title=$title; $this->text = $text; $this->created_at = new \DateTime(); $this->user->addPost($this); } public function addComment($comment) { $this->comment[] = $comment; } public function __clone() { $this->title = $this->title . "New Post"; $this->user->addPost($this); $this->comments = []; $this->created_at = new \DateTime(); } } class User { private $firstname; private $posts = []; public function __construct($firstname) { $this->firstname = $firstname; } public function addPost($post) { $this->posts[] = $post; } } $user = new User('User'); $post = new Post($user,'First Post','Hello world'); $post->addComment('Hello'); $post2 = clone $post; var_dump($post2); var_dump($post);