Prototype Pattern
태그 :
- 개념
- - 지정한 클래스의 인스턴스가 반드시 1개만 존재하도록 하는 패턴 :: 딱 한 객체만 생성되도록 한다
I. 의도
프로토타입 인스턴스를 사용해 생성할 객체의 종류를 명시하고 이렇게 만들어진 프로토타입을 복사해 새로운 객체 생성
정의: 클래스로부터 인스턴스를 만드는것이 아니라 인스턴스를 복사해서 새로운 인스턴스를 만든다
어떻게è Clone()이라는 메소드를 통해 자신의 인스턴스를 복사해서 새로운 인스턴스 생성
(Clone : 단일세포 또는 개체로부터 무성적(無性的)인 증식에 의하여 생긴 유전적으로 동일한 세포군 또는 개체군을 말함)
: 어떤 클래스의 인스턴스를 만드는것이 자원/시간을 많이 잡아 먹거나 복잡한 경우에는 프로토타입 패턴을 쓴다.
II. 활용
- 제품의 생성, 합성, 표현 방법에 독립적인 제품을 만들고자 할 때
- 런타임시 만들 인스턴스의 클래스를 명세할 수 있을 때
- 클래스 계층도와 병렬성을 갖는 팩토리 클래스의 계층을 피해야 할 경우
- 클래스의 인스터스들이 서로 다른 상태조합 중에 어느 하나를 가질 때
- 종류가 너무 많아 한개의 클래스로 할 수 없는 경우
- 클래스로부터 인스턴스를 생성하기 어려운 경우
- 프레임웍크와 생성할 인스턴스를 분리하고 싶은 경우
※ 클라이언트에서는 새로운 인스턴스를 만드는 복잡한 과정을 몰라도 된다.
※ 클라이언트에서는 구체적인 형식을 모르더라도 객체를 생성할수 있다.
※ 상황에 따라서 객체를 새로 생성하는 것보다 객체를 복사하는것이 더 효율적이다.
III. 결과
- 추상 팩토리, 빌더와 비슷한 결과. 클라이언트에게 어떤 구체적인 제품이 있는지를 감출 수 있기 때문에, 클라이언트가 상대해야 하는 클래스 수가 적어지게 되고, 이로써 수정없이도 애플리케이션에 종속된 클래스들과 동작할 수 있게 된다
- 런타임에 새로운 제품을 삽입하고 삭제할 수 있다
- 값들을 다양화함으로써 새로운 객체를 명세한다 – 새로운 클래스를 생성할 필요없이 객체에 정의된 변수 값에 따라 행위를 변경할 수 있다
- 구조를 다양화함으로써 새로운 객체를 정의할 수 있다.
- 서브클래스의 수를 줄인다
- 동적으로 클래스에 따라 애플리케이션을 형성할 수 있다.
- Prototype의 서브클래스가 clone() 오퍼레이션을 구현해야 하는데 clone()오퍼레이션 구현이 어려울 경우 프로토타입 패턴 적용 어렵다
관련 패턴: Prototype 패턴과 Abstract Factory 패턴은 어떤 면에서 경쟁적인 관계이다. 물론 함께 사용될 수 있지만 Abstract Factory 패턴의 경우 프로토타입 집합을 저장하고 있다가 필요할 때 복제하여 제품 객체를 반환하도록 사용할 수 있다. 만약 Composite 패턴과 Decorator 패턴을 많이 사용해야 한다면 Prototype 패턴을 사용하는 것이 좋다
- Prototype: 자신을 복제하는데 필요한 인터페이스를 정의한다.
- ConcretePrototype: 자신을 복제하는 오퍼레이션을 구현한다.
- Client: prototype 에 복제를 요청함으로써 새로운 객체를 생성한다.
소스
적용전 |
적용후 |
class Stooge { ------------------------ Super Class public: virtual void slap_stick() = 0; };
class Larry: public Stooge { --------------상속 public: void slap_stick() { cout << "Larry: poke eyes\n"; } }; class Moe: public Stooge { public: void slap_stick() { cout << "Moe: slap head\n"; } }; class Curly: public Stooge { public: void slap_stick() { cout << "Curly: suffer abuse\n"; } };
int main() { vector roles; int choice;
while (true) { cout << "Larry(1) Moe(2) Curly(3) Go(0): "; cin >> choice; if (choice == 0) break; else if (choice == 1) roles.push_back(new Larry); else if (choice == 2) roles.push_back(new Moe); else roles.push_back(new Curly); } for (int i = 0; i < roles.size(); i++) roles[i]->slap_stick(); for (int i = 0; i < roles.size(); i++) delete roles[i]; } |
class Stooge { public: virtual Stooge* clone() = 0; virtual void slap_stick() = 0; };
class Factory { public: static Stooge* make_stooge( int choice ); private: static Stooge* s_prototypes[4]; };
int main() { vector roles; int choice;
while (true) { cout << "Larry(1) Moe(2) Curly(3) Go(0): "; cin >> choice; if (choice == 0) break; roles.push_back( Factory::make_stooge( choice ) ); }
for (int i=0; i < roles.size(); ++i) roles[i]->slap_stick(); for (int i=0; i < roles.size(); ++i) delete roles[i]; }
class Larry : public Stooge { public: Stooge* clone() { return new Larry; } void slap_stick() { cout << "Larry: poke eyes\n"; } }; class Moe : public Stooge { public: Stooge* clone() { return new Moe; } void slap_stick() { cout << "Moe: slap head\n"; } }; class Curly : public Stooge { public: Stooge* clone() { return new Curly; } void slap_stick() { cout << "Curly: suffer abuse\n"; } };
Stooge* Factory::s_prototypes[] = { 0, new Larry, new Moe, new Curly }; Stooge* Factory::make_stooge( int choice ) { return s_prototypes[choice]->clone(); }
|