프로토타입 패턴

프로토타입 패턴()은 소프트웨어 디자인 패턴 용어로, 생성할 객체들의 타입이 프로토타입인 인스턴스로부터 결정되도록 하며, 인스턴스는 새 객체를 만들기 위해 자신을 복제(clone)하게 된다.
패턴을 구현하려면, 우선 codice_2 메소드를 선언하는 추상 베이스 클래스를 하나 만든다. 다형적 생성자(polymorphic constructor) 기능이 필요한 클래스가 있다면, 그것을 앞에서 만든 클래스를 상속받게 한 후, codice_2 메소드 내의 코드를 구현한다.
원칙.
객체 생성과 관련된 패턴들은 서로 영역이 겹치는 면이 있다. 프로토타입 패턴과 추상 팩토리 패턴 중 어느 하나가 적용될 수 있는 경우가 있다. 추상 팩토리 패턴이 프로토타입들의 집합을 갖고있다가, 클론(clone)한 뒤 프로덕트(product) 객체를 반환할 수도 있다.
추상 팩토리 패턴, 빌더 패턴, 프로토타입 패턴은 각 구현에 있어서 싱글턴 패턴을 활용할 수 있다.
다시 말해 추상 팩토리 클래스는 종종 팩토리 메소드와 함께 구현하거나, 프로토타입을 이용해서 구현되기도 한다.
보통 설계는 처음에는 팩토리 메소드로 출발한다. 다음에 설계자의 재량에 따라 추상 팩토리 패턴, 빌더 패턴, 프로토타입 패턴으로 바뀔 수 있다.
프로토타입은 서브클래싱을 필요로 하지 않는다. 하지만 "초기화" 동작을 필요로 한다. 팩토리 메서드 패턴은 서브클래싱을 필요로 하나, "초기화" 동작은 필요로 하지 않는다.
설계자는 컴포지트 패턴이나 데코레이터 패턴을 매우 많이 사용한 무거운 설계를 프로토타입을 사용하여 더 좋게 만들 수 있다.
원칙은 "런타임"에 또 다른 "객체"를 생성한다는 것이다. 다시 말해 이 시점에 가서 클로닝(cloning)을 하는 객체의 "실제 복사본"이 만들어지는 것이다. "실제 복사본"이라는 말은 새로 생성되는 객체가 클로닝(cloning) 당하는 객체의 애트리뷰트와 똑같은 애트리뷰트를 가질 것이라는 말이다. 반면에, "codice_1"를 이용해 객체를 생성했다면, 새로이 생성된 객체의 애트리뷰트들은 초기값을 가질 것이다.
예를 들면, 은행 계좌 입출금 트랜잭션을 수행하는 시스템을 가정해 보자. 프로그래머는 은행 이용자의 계좌 정보를 갖고 있는 객체를 하나 복사한다. 그 객체를 가지고 그 객체 상에다 은행 입출금 트랜잭션을 수행한다. 그 다음 원래의 객체를 이 객체로 바꿔치기한다. 프로그래머는 이런 경우 codice_1 대신 codice_6을 쓴다.
예제.
C++.
using namespace std;
enum RECORD_TYPE_en
 CAR,
 BIKE,
 PERSON
 * Record is the Prototype
class Record
 public :
 virtual Record* Clone() const=0;
 virtual void Print() const=0;
 * CarRecord is Concrete Prototype
class CarRecord: public Record
 private :
 string m_oStrCarName;
 uint32_t m_ui32ID;
 public :
 CarRecord(const string&amp; _oStrCarName, uint32_t _ui32ID)
 : Record(), m_oStrCarName(_oStrCarName),
 m_ui32ID(_ui32ID)
 CarRecord(const CarRecord&amp; _oCarRecord)
 : Record()
 m_oStrCarName = _oCarRecord.m_oStrCarName;
 m_ui32ID = _oCarRecord.m_ui32ID;
 CarRecord* Clone() const
 return new CarRecord(*this);
 void Print() const
 cout « "Car Record" « endl
 « "Name : " « m_oStrCarName « endl
 « "Number: " « m_ui32ID « endl « endl;
};
 * BikeRecord is the Concrete Prototype
class BikeRecord: public Record
 private :
 string m_oStrBikeName;
 uint32_t m_ui32ID;
 public :
 BikeRecord(const string&amp; _oStrBikeName, uint32_t _ui32ID)
 : Record(), m_oStrBikeName(_oStrBikeName),
 m_ui32ID(_ui32ID)
 BikeRecord(const BikeRecord&amp; _oBikeRecord)
 : Record()
 m_oStrBikeName = _oBikeRecord.m_oStrBikeName;
 m_ui32ID = _oBikeRecord.m_ui32ID;
 BikeRecord* Clone() const
 return new BikeRecord(*this);
 void Print() const
 cout « "Bike Record" « endl
 « "Name : " « m_oStrBikeName « endl
 « "Number: " « m_ui32ID « endl « endl;
};
 * PersonRecord is the Concrete Prototype
class PersonRecord: public Record
 private :
 string m_oStrPersonName;
 uint32_t m_ui32Age;
 public :
 PersonRecord(const string&amp; _oStrPersonName, uint32_t _ui32Age)
 : Record(), m_oStrPersonName(_oStrPersonName),
 m_ui32Age(_ui32Age)
 PersonRecord(const PersonRecord&amp; _oPersonRecord)
 : Record()
 m_oStrPersonName = _oPersonRecord.m_oStrPersonName;
 m_ui32Age = _oPersonRecord.m_ui32Age;
 Record* Clone() const
 return new PersonRecord(*this);
 void Print() const
 cout « "Person Record" « endl
 « "Name: " « m_oStrPersonName « endl
 « "Age : " « m_ui32Age « endl « endl ;
};
 * RecordFactory is the client
class RecordFactory
 private :
 map&lt;RECORD_TYPE_en, Record* &gt; m_oMapRecordReference;
 public :
 RecordFactory()
 m_oMapRecordReference[CAR] = new CarRecord("Ferrari", 5050);
 m_oMapRecordReference[BIKE] = new BikeRecord("Yamaha", 2525);
 m_oMapRecordReference[PERSON] = new PersonRecord("Tom", 25);
 ~RecordFactory()
 delete m_oMapRecordReference[CAR];
 delete m_oMapRecordReference[BIKE];
 delete m_oMapRecordReference[PERSON];
 Record* CreateRecord(RECORD_TYPE_en enType)
 return m_oMapRecordReference[enType]-&gt;Clone();
};
int main()
 RecordFactory* poRecordFactory = new RecordFactory();
 Record* poRecord;
 poRecord = poRecordFactory-&gt;CreateRecord(CAR);
 poRecord-&gt;Print();
 delete poRecord;
 poRecord = poRecordFactory-&gt;CreateRecord(BIKE);
 poRecord-&gt;Print();
 delete poRecord;
 poRecord = poRecordFactory-&gt;CreateRecord(PERSON);
 poRecord-&gt;Print();
 delete poRecord;
 delete poRecordFactory;
 return 0;
C#.
public enum RecordType
 Car,
 Person
/// &lt;summary&gt;
/// Record is the Prototype
/// &lt;/summary&gt;
public abstract class Record
 public abstract Record Clone();
/// &lt;summary&gt;
/// PersonRecord is the Concrete Prototype
/// &lt;/summary&gt;
public class PersonRecord: Record
 string name;
 int age;
 public override Record Clone()
 return (Record)this.MemberwiseClone(); // default shallow copy
/// &lt;summary&gt;
/// CarRecord is another Concrete Prototype
/// &lt;/summary&gt;
public class CarRecord: Record
 string carname;
 Guid id;
 public override Record Clone()
 CarRecord clone = (Record)this.MemberwiseClone(); // default shallow copy
 clone.id = Guid.NewGuid(); // always generate new id
 return clone;
/// &lt;summary&gt;
/// RecordFactory is the client
/// &lt;/summary&gt;
public class RecordFactory
 private static Dictionary&lt;RecordType, Record&gt; _prototypes =
 new Dictionary&lt;RecordType, Record&gt;();
 /// &lt;summary&gt;
 /// Constructor
 /// &lt;/summary&gt;
 public RecordFactory()
 _prototypes.Add(RecordType.Car, new CarRecord());
 _prototypes.Add(RecordType.Person, new PersonRecord());
 /// &lt;summary&gt;
 /// The Factory method
 /// &lt;/summary&gt;
 public Record CreateRecord(RecordType type)
 return _prototypes[type].Clone();
Java.
/** Prototype Class **/
public class Cookie implements Cloneable {
 public Object clone() {
 try {
 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;
 catch(CloneNotSupportedException e) {
 e.printStackTrace();
 return null;
/** Concrete Prototypes to clone **/
/** 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() {
 return (Cookie)cookie.clone();
 public static void main(String args[]) {
 Cookie tempCookie = null;
 Cookie prot = new CoconutCookie();
 CookieMachine cm = new CookieMachine(prot);
 for (int i=0; i&lt;100; i++)
 tempCookie = cm.makeCookie();
Python.
 from copy import copy, deepcopy
 class Prototype:
 def __init__(self):
 def registerObject(self, name, obj):
 register an object.
 self._objs[name] = obj
 def unregisterObject(self, name):
 """unregister an object"""
 del self._objs[name]
 def clone(self, name, **attr):
 """clone a registered object and add/replace attr"""
 obj = deepcopy(self._objs[name])
 obj.__dict__.update(attr)
 return obj
 # create another instance, w/state, of an existing instance of unknown class/state
 g = Graphic() # non-cooperative form
 shallow_copy_of_g = copy(g)
 deep_copy_of_g = deepcopy(g)
 class Graphic:
 def clone(self):
 return copy(self)
 g = Graphic() # cooperative form
 copy_of_g = g.clone()
PHP.
PHP 5에서는, 객체는 레퍼런스 형태로 전달된다(pass by reference).
값 형태로 전달하기 위해서는, "매직 펑션" __clone()을 써야한다.
이러한 까닭으로 PHP 5에서는 프로토타입 패턴을 구현하기 매우 쉽다.
&lt;?php
abstract class BookPrototype {
 protected $title;
 protected $topic;
 abstract function __clone();
 function getTitle() {
 return $this-&gt;title;
 function setTitle($titleIn) {
 $this-&gt;title = $titleIn;
 function getTopic() {
 return $this-&gt;topic;
class PHPBookPrototype extends BookPrototype {
 function __construct() {
 $this-&gt;topic = 'PHP';
 function __clone() {
class SQLBookPrototype extends BookPrototype {
 function __construct() {
 $this-&gt;topic = 'SQL';
 function __clone() {
 writeln('BEGIN TESTING PROTOTYPE PATTERN');
 writeln(");
 $phpProto = new PHPBookPrototype();
 $sqlProto = new SQLBookPrototype();
 $book1 = clone $sqlProto;
 $book1-&gt;setTitle('SQL For Cats');
 writeln('Book 1 topic: '.$book1-&gt;getTopic());
 writeln('Book 1 title: '.$book1-&gt;getTitle());
 writeln(");
 $book2 = clone $phpProto;
 $book2-&gt;setTitle('OReilly Learning PHP 5');
 writeln('Book 2 topic: '.$book2-&gt;getTopic());
 writeln('Book 2 title: '.$book2-&gt;getTitle());
 writeln(");
 $book3 = clone $sqlProto;
 $book3-&gt;setTitle('OReilly Learning SQL');
 writeln('Book 3 topic: '.$book3-&gt;getTopic());
 writeln('Book 3 title: '.$book3-&gt;getTitle());
 writeln(");
 writeln('END TESTING PROTOTYPE PATTERN');
 function writeln($line_in) {
 echo $line_in."&lt;br/&gt;";
?&gt;
출력은 다음과 같다.