stringtranslate.com

Шаблон прототипа

Шаблон прототипа — это шаблон творческого проектирования при разработке программного обеспечения . Он используется, когда типы создаваемых объектов определяются прототипным экземпляром , который клонируется для создания новых объектов. Этот шаблон используется для того, чтобы избежать подклассов создателя объекта в клиентском приложении, как это делает шаблон фабричного метода , а также для того, чтобы избежать неизбежных затрат на создание нового объекта стандартным способом (например, с использованием ключевого слова ' new '), когда он является непомерно дорогим для данного приложения.

Для реализации шаблона клиент объявляет абстрактный базовый класс , который определяет чистый виртуальный метод clone() . Любой класс, которому требуется возможность « полиморфного конструктора », наследуется от абстрактного базового класса и реализует операцию clone() .

Клиент вместо написания кода, который вызывает оператор «новый» для жестко закодированного имени класса, вызывает метод clone() прототипа, вызывает фабричный метод с параметром , обозначающим конкретный желаемый производный класс , или вызывает clone() с помощью какого-либо механизма, предусмотренного другим шаблоном проектирования.

Митотическое деление клетки, в результате которого образуются две идентичные клетки, является примером прототипа, который играет активную роль в копировании себя и, таким образом, демонстрирует паттерн прототипа. Когда клетка делится, образуются две клетки одинакового генотипа. Другими словами, клетка клонирует себя. [1]

Обзор

Шаблон проектирования прототипа — один из 23 шаблонов проектирования «Банды четырех» , которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторно использовать. [2] : 117 

Шаблон проектирования прототипа решает такие проблемы, как: [3]

Создание объектов непосредственно внутри класса, который требует (использует) эти объекты, является негибким, поскольку оно связывает класс с конкретными объектами во время компиляции и делает невозможным указать, какие объекты создавать во время выполнения.

Шаблон проектирования прототипа описывает, как решить такие проблемы:

Это позволяет настраивать класс с различными Prototypeобъектами, которые копируются для создания новых объектов, и, более того, Prototypeобъекты можно добавлять и удалять во время выполнения.
См. также класс UML и диаграмму последовательности ниже.

Состав

Класс UML и диаграмма последовательности

Пример класса UML и диаграммы последовательности для шаблона проектирования прототипа.

В приведенной выше диаграмме классов UML класс относится к интерфейсу для клонирования файла . Класс реализует интерфейс, создавая свою копию. Диаграмма последовательности UML показывает взаимодействие во время выполнения: объект вызывает объект , который создает и возвращает свою копию ( объект).ClientPrototypeProductProduct1Prototype
Clientclone()prototype:Product1product:Product1

Диаграмма классов UML

Диаграмма классов UML , описывающая шаблон проектирования прототипа

Эмпирические правила

Иногда творческие шаблоны пересекаются — бывают случаи, когда уместны либо прототип, либо абстрактная фабрика . В других случаях они дополняют друг друга: абстрактная фабрика может хранить набор прототипов, из которых можно клонировать и возвращать объекты продукта. [2] : 126  Абстрактная фабрика, сборщик и прототип могут использовать синглтон в своих реализациях. [2] : 81, 134  Абстрактные фабричные классы часто реализуются с помощью фабричных методов (создание посредством наследования ), но их можно реализовать с помощью прототипа (создание посредством делегирования ). [2] : 95 

Часто проекты начинаются с использования фабричного метода (менее сложного, более настраиваемого, подклассы разрастаются) и развиваются в сторону абстрактной фабрики, прототипа или конструктора (более гибкого, более сложного) по мере того, как дизайнер обнаруживает, где требуется большая гибкость. [2] : 136 

Прототип не требует создания подклассов, но требует операции «инициализации». Фабричный метод требует создания подклассов, но не требует инициализации. [2] : 116 

Проекты, в которых интенсивно используются шаблоны композитов и декораторов , часто также могут извлечь выгоду из Prototype. [2] : 126 

Общие рекомендации по программированию предлагают использовать этот clone()метод при создании дубликата объекта во время выполнения, чтобы гарантировать, что он точно отражает исходный объект. Этот процесс, известный как клонирование объекта, создает новый объект с атрибутами, идентичными клонируемому. Альтернативно, создание экземпляра класса с использованием newключевого слова генерирует объект со значениями атрибутов по умолчанию.

Например, в контексте разработки системы управления транзакциями по банковским счетам может возникнуть необходимость дублировать объект, содержащий информацию о счете, для проведения транзакций с сохранением исходных данных. В таких сценариях использование этого clone()метода предпочтительнее, чем использование newдля создания экземпляра нового объекта.

Пример

Эта реализация C++11 основана на реализации до C++98, описанной в книге.

#include <iostream> enum Direction { Север , Юг , Восток , Запад };     класс MapSite { public : virtual void enter () = 0 ; виртуальный MapSite * clone () const = 0 ; виртуальный ~ MapSite () = по умолчанию ; };                 class Room : public MapSite { public : Room () : roomNumber ( 0 ) {} Room ( int n ) : roomNumber ( n ) {} void setSide ( Direction d , MapSite * ms ) { std :: cout << "Room: :setSide " << d << ' ' << ms << '\n' ; } virtual void enter () {} virtual Room * clone () const { // реализует операцию клонирования себя. вернуть новую комнату ( * this ); } Комната и оператор = ( const Комната & ) = удалить ; частный : int roomNumber ; };                                                   класс Wall : public MapSite { public : Wall () {} virtual void enter () {} virtual Wall * clone () const { return new Wall ( * this ); } };                    class Door : public MapSite { public : Door ( Room * r1 = nullptr , Room * r2 = nullptr ) : room1 ( r1 ), room2 ( r2 ) {} Door ( const Door и другое ) : room1 ( other . room1 ), room2 ( other.room2 ) {} virtual void enter () {} virtual Door * clone ( ) const { return new Door ( * this ) ; } Virtual void инициализировать ( Комната * r1 , Комната * r2 ) { room1 = r1 ; комната2 = г2 ; } Дверь и оператор = ( const Дверь & ) = удалить ; личное : Комната * комната1 ; Комната * комната2 ; };                                                          class Maze { public : void addRoom ( Room * r ) { std :: cout << "Maze::addRoom " << r << '\n' ; } Room * roomNo ( int ) const { return nullptr ; } виртуальный лабиринт * clone () const { return new Maze ( * this ); } виртуальный ~ Maze () = по умолчанию ; };                                  класс MazeFactory { public : MazeFactory () = по умолчанию ; виртуальный ~ MazeFactory () = по умолчанию ;          виртуальный лабиринт * makeMaze () const { return new Maze ; } виртуальная стена * makeWall () const { return new Wall ; } виртуальная комната * makeRoom ( int n ) const { return new Room ( n ); } virtual Door * makeDoor ( Room * r1 , Room * r2 ) const { return new Door ( r1 , r2 ); } };                                        класс MazePrototypeFactory : public MazeFactory { public : MazePrototypeFactory ( Maze * m , Wall * w , Room * r , Door * d ) : PrototypeMaze ( m ), PrototypeRoom ( r ), PrototypeWall ( w ), PrototypeDoor ( d ) {} виртуальный лабиринт * makeMaze () const { // создает новый объект, прося прототип клонировать себя. вернуть прототипMaze -> клон (); } Виртуальная комната * makeRoom ( int ) const { returnprototypeRoom -> clone () ; } виртуальная стена * makeWall () const { returnprototypeWall - > clone (); } virtual Door * makeDoor ( Room * r1 , Room * r2 ) const { Door * Door = PrototypeDoor -> clone (); дверь -> инициализировать ( r1 , r2 ); обратная дверь ; } MazePrototypeFactory ( const MazePrototypeFactory & ) = удалить ; MazePrototypeFactory & оператор = ( const MazePrototypeFactory & ) = удалить ; частный : Maze * prototypeMaze ; Комната * прототипКомната ; Стена * прототипСтена ; Дверь * прототипДверь ; };                                                                             // Если createMaze параметризован различными прототипными объектами комнаты, двери и стены, которые затем копируются и добавляются в лабиринт, то вы можете изменить композицию лабиринта, заменив эти прототипические объекты другими. Это пример паттерна Прототип (133).класс MazeGame { public : Maze * createMaze ( MazePrototypeFactory & m ) { Maze * aMaze = m . сделать лабиринт (); Комната * r1 = м . сделатьКомнату ( 1 ); Комната * r2 = м . сделатьКомнату ( 2 ); Дверь * Дверь = м . сделатьДверь ( r1 , r2 ); aMaze -> addRoom ( r1 ); aMaze -> addRoom ( r2 ); r1 -> setSide ( North , m.makeWall ( )) ; r1 -> setSide ( Восток , Дверь ); r1 -> setSide ( Юг , м . makeWall ()); r1 -> setSide ( West , m.makeWall ( ) ); r2 - > setSide ( North , m.makeWall ( )); r2 -> setSide ( Восток , м . makeWall ()); r2 -> setSide ( Юг , м . makeWall ()); r2 -> setSide ( Запад , Дверь ); вернуть лабиринт ; } };                                            int main () { игра MazeGame ; MazePrototypeFactory simpleMazeFactory ( новый лабиринт , новая стена , новая комната , новая дверь ); игра . createMaze ( simpleMazeFactory ); }              

Вывод программы:

Лабиринт :: addRoom 0x1160f50 Лабиринт :: addRoom 0x1160f70 Комната :: setSide 0 0x11613c0 Комната :: setSide 2 0x1160f90 Комната :: setSide 1 0x11613e0 Комната :: setSide 3 0x1161400 Комната :: setSide 0 0x1161420 Комната :: setSide 2 0x1161440 Комната :: setSide 1 0x1161460 Комната :: setSide 3 0x1160f90                  

пример С++

Обсуждение шаблона проектирования, а также полный иллюстративный пример реализации с использованием проектирования полиморфных классов представлены в аннотациях C++.

Смотрите также

Рекомендации

  1. ^ Дуэлл, Майкл (июль 1997 г.). «Непрограммные примеры шаблонов проектирования». Журнал «Объект» . 7 (5): 54. ISSN  1055-3614.
  2. ^ abcdefg Гамма, Эрих ; Хелм, Ричард; Джонсон, Ральф ; Влиссидес, Джон (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Аддисон-Уэсли. ISBN 0-201-63361-2.
  3. ^ «Шаблон проектирования прототипа - проблема, решение и применимость» . w3sDesign.com . Проверено 17 августа 2017 г.