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