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();

}

 

 

 

 

댓글