- Прототип (шаблон проектирования)
-
Шаблон проектирования Прототип Prototype Тип: порождающий
Описан в Design Patterns Да
Прототип, (англ. Prototype) — порождающий шаблон проектирования.
Содержание
Назначение
Задаёт виды создаваемых объектов с помощью экземпляра-прототипа и создаёт новые объекты путём копирования этого прототипа.
Проще говоря, это паттерн создания объекта через клонирование другого объекта вместо создания через конструктор.
Применимость
Паттерн используется чтобы:
- избежать дополнительных усилий по созданию объекта стандартным путем (имеется в виду использование ключевого слова 'new', когда вызывается конструктор не только самого объекта, но и конструкторы всей иерархии предков объекта), когда это непозволительно дорого для приложения.
- избежать наследования создателя объекта (object creator) в клиентском приложении, как это делает паттерн abstract factory.
Используйте этот шаблон проектирования, когда система не должна зависеть от того, как в ней создаются, компонуются и представляются продукты:
- инстанцируемые классы определяются во время выполнения, например с помощью динамической загрузки;
- для того чтобы избежать построения иерархий классов или фабрик, параллельных иерархии классов продуктов;
- экземпляры класса могут находиться в одном из нескольких различных состояний. Может оказаться удобнее установить соответствующее число прототипов и клонировать их, а не инстанцировать каждый раз класс вручную в подходящем состоянии.
Примеры
Пример на C++
Исходный текст на языке C++class Meal { public: virtual ~Meal(); virtual void eat() = 0; virtual Meal *clone() const = 0; //... }; class Spaghetti : public Meal { public: Spaghetti( const Spaghetti &); void eat(); Spaghetti *clone() const { return new Spaghetti( *this ); } //... };
Пример на Java
Исходный текст на языке Java/** * Prototype Class */ public class Cookie implements Cloneable { @Override public Cookie clone() throws CloneNotSupportedException { // call Object.clone() Cookie copy = (Cookie) super.clone(); //In an actual implementation of this pattern you might now change references to //the expensive to produce parts from the copies that are held inside the prototype. return copy; } } /** * Concrete Prototypes to clone */ public class CoconutCookie extends Cookie { }
/** * Client Class */ public class CookieMachine { private Cookie cookie; // Could have been a private Cloneable cookie. public CookieMachine(Cookie cookie) { this.cookie = cookie; } public Cookie makeCookie() throws CloneNotSupportedException { return (Cookie) this.cookie.clone(); } public static void main(String args[]) throws CloneNotSupportedException { Cookie tempCookie = null; Cookie prot = new CoconutCookie(); CookieMachine cm = new CookieMachine(prot); for (int i = 0; i < 100; i++) tempCookie = cm.makeCookie(); } }
Пример на C#
Исходный текст на языке C#using System; namespace Prototype { class MainApp { static void Main() { // Create two instances and clone each Prototype p1 = new ConcretePrototype1("I"); Prototype c1 = p1.Clone(); Console.WriteLine ("Cloned: {0}", c1.Id); Prototype p2 = new ConcretePrototype2("II"); Prototype c2 = p2.Clone(); Console.WriteLine ("Cloned: {0}", c2.Id); // Wait for user Console.Read(); } } // "Prototype" abstract class Prototype { private string id; // Constructor public Prototype(string id) { this.id = id; } // Property public string Id { get{ return id; } } public abstract Prototype Clone(); } // "ConcretePrototype1" class ConcretePrototype1 : Prototype { // Constructor public ConcretePrototype1(string id) : base(id) { } public override Prototype Clone() { // Shallow copy return (Prototype)this.MemberwiseClone(); } } // "ConcretePrototype2" class ConcretePrototype2 : Prototype { // Constructor public ConcretePrototype2(string id) : base(id) { } public override Prototype Clone() { // Shallow copy return (Prototype)this.MemberwiseClone(); } } }
Пример на PHP
Исходный текст на языке PHP<?php /** * Иерархия допустимых классов для создания прототипов */ abstract class Terrain {} abstract class Sea extends Terrain {} class EarthSea extends Sea {} class MarsSea extends Sea {} class VenusSea extends Sea {} abstract class Plains extends Terrain {} class EarthPlains extends Plains {} class MarsPlains extends Plains {} class VenusPlains extends Plains {} abstract class Forest extends Terrain {} class EarthForest extends Forest {} class MarsForest extends Forest {} class VenusForest extends Forest {} /** * Определение логики фабрики прототипов */ class TerrainFactory { private $sea; private $forest; private $plains; public function __construct( Sea $sea, Plains $plains, Forest $forest ) { $this->sea = $sea; $this->plains = $plains; $this->forest = $forest; } function getSea( ) { return clone $this->sea; } function getPlains( ) { return clone $this->plains; } function getForest( ) { return clone $this->forest; } } /** * Создание фабрики с заданными параметрами прототипа */ $prototypeFactory = new TerrainFactory( new EarthSea(), new MarsPlains(), new VenusForest() ); /** * Создание заданных объектов путём клонирования */ $sea = $prototypeFactory->getSea(); $plains = $prototypeFactory->getPlains(); $forest = $prototypeFactory->getForest();
Пример на Ruby
Исходный текст на языке Rubymodule Prototype # "Prototype" class Prototype # Property # свойство id изначально присутствует у каждого объекта, поэтому воспользуемся свойством name attr_reader :name # Constructor def initialize name @name = name end end end # Create an instance and clone it p1 = Prototype::Prototype.new "my name" # объект класса Prototype создается традиционны путем - методом new p2 = p1.clone # метод clone существует у каждого объекта изначально - его не нужно определять puts "p1.id = #{p1.id}, p2.id = #{p2.id}" # будут напечатаны разные id puts "p1.name = #{p1.name}, p2.name = #{p2.name}" # будут напечатаны одинаковые name - "my name" # Wait for user gets
Пример на VB.NET
Исходный текст на языке VB.NETNamespace Prototype Class MainApp Shared Sub Main() ' Создание двух экземпляров и клонирование каждого Dim p1 As Prototype = New ConcretePrototype1("I") Dim c1 As Prototype = p1.Clone() Console.WriteLine("Cloned: {0}", c1.Id) Dim p2 As Prototype = New ConcretePrototype2("II") Dim c2 As Prototype = p2.Clone() Console.WriteLine("Cloned: {0}", c2.Id) Console.Read() End Sub End Class ' "Prototype" MustInherit Class Prototype Private m_id As String ' Конструктор Public Sub New(ByVal id As String) Me.m_id = id End Sub ' Свойство Public ReadOnly Property Id() As String Get Return m_id End Get End Property Public MustOverride Function Clone() As Prototype End Class ' "ConcretePrototype1" Class ConcretePrototype1 Inherits Prototype ' Конструктор Public Sub New(ByVal id As String) MyBase.New(id) End Sub Public Overrides Function Clone() As Prototype ' Неполная копия Return DirectCast(Me.MemberwiseClone(), Prototype) End Function End Class ' "ConcretePrototype2" Class ConcretePrototype2 Inherits Prototype ' Конструктор Public Sub New(ByVal id As String) MyBase.New(id) End Sub Public Overrides Function Clone() As Prototype ' Неполная копия Return DirectCast(Me.MemberwiseClone(), Prototype) End Function End Class End Namespace
Пример на Delphi
Исходный текст на языке Delphiprogram PrototypePattern; {$APPTYPE CONSOLE} uses SysUtils; type TPrototype = class public function Clone: TPrototype; virtual; abstract; end; type TPrototypeType = class(TPrototype) private FID: Integer; FInfo: string; public property ID: Integer read FID write FID; property Info: String read FInfo write FInfo; function Clone: TPrototype; override; end; function TPrototypeType.Clone: TPrototype; begin Result:= TPrototypeType.Create; with TPrototypeType(Result) do begin ID:= Self.ID; Info:= Self.Info; end; end; var vConcretePrototype1: TPrototypeType; vConcretePrototype2: TPrototypeType; vClone: TPrototype; begin vConcretePrototype1:= TPrototypeType.Create; with vConcretePrototype1 do begin ID:= 10; Info:= ' Prototype1!'; end; vConcretePrototype2:= TPrototypeType.Create; with vConcretePrototype2 do begin ID:= 11; Info:= ' Prototype2!'; end; vClone:= vConcretePrototype1.Clone; with TPrototypeType(vClone) do begin Write(ID); Write(Info); end; vClone.Free; WriteLn; vClone:= vConcretePrototype2.Clone; with TPrototypeType(vClone) do begin Write(ID); Write(Info); end; vClone.Free; vConcretePrototype1.Free; vConcretePrototype2.Free; ReadLn; end.
Литература
- Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес Приемы объектно-ориентированного проектирования. Паттерны проектирования = Design Patterns: Elements of Reusable Object-Oriented Software. — СПб: «Питер», 2007. — С. 366. — ISBN 978-5-469-01136-1 (также ISBN 5-272-00355-1)
См. также
Ссылки
- Паттерн Prototype (Прототип) — назначение, описание, два варианта реализации (С++), достоинства и недостатки
Шаблоны проектирования Основные Порождающие Абстрактная фабрика • Объектный пул • Одиночка • Отложенная инициализация • Прототип • Строитель • Фабричный метод
Структурные Поведенческие Интерпретатор • Итератор • Команда • Наблюдатель • Посетитель • Посредник • Состояние • Стратегия • Хранитель • Цепочка обязанностей • Шаблонный метод
Блокировка с двойной проверкой • Однопоточное выполнение • Планировщик Категория:- Шаблоны проектирования
Wikimedia Foundation. 2010.