Programming Languange/디자인 패턴

디자인 패턴 (Design Patterns) - 프로토타입 패턴

타자치는 문돌이

프로토타입 패턴은 비슷한 객체를 여러개 만들 때 객체의 생성이 비용이 많이 들거나 복잡할 때, 또는 새로 생성하는 것보다 복사해서 값 한두개만 바꾸는 것이 더 빠른 경우 사용한다.

객체를 생성하는 방법은 2가지이다.

  1. new를 사용해 새 객체를 만들거나
  2. 기존의 객체를 복사해 사용하면 된다.
    프로토타입 패턴은 복사를 사용해 객체를 생성하는 방법이다.

복사를 통해 생성하면

  1. 초기화를 하지 않아도 된다.
  2. 기존 값까지 복사된다.
    따라서 초기화 과정이 줄어 들고, 복잡한 객체를 더 쉽게 생성할 수 있다는 장점이 있다.

구현

Class의 복사는 2가지 종류가 있다.
먼저 Soft Copy는 복사를 해도 실제로 변수를 복사하지 않는다. 복제된 변수를 수정하면 원본도 함께 복사된다.
Deep Copy는 물리적으로 변수를 복사한다. 따라서 메모리에는 변수를 저장하기 위한 새 저장공간이 할당된다.
프로토타입 패턴을 위해선 Deep Copy를 통해 프로토타입을 복사하는 Clone 메소드가 필요하다.

class Prototype
{
private:
    std::string info;
public:
    Prototype(const std::string& info) : info(info) {}

    // Clone Method
    Prototype* clone() const override
    {
        return new ConcretePrototype(*this);
    }
};

여기서 더 나아가 보자.
프로토타입 패턴을 구현할 때는 보통 Prototype Interface를 정의해 사용한다.
Interface를 상속 받는 클래스라면 구체적인 클래스에 의존하지 않고도 객체 생성이 가능하여 유연한 복제가 가능하다.

Prototype

// Prototype Interface
class Prototype
{
public:
    virtual Prototype* clone() const = 0;  // 가상 함수
    #virtual void printInfo() const = 0;
};

Concrete Prototype


// Concrete Prototype Class 1
class ConcretePrototype1 : public Prototype
{
private:
    std::string info;
public:
    ConcretePrototype1(const std::string& info) : info(info) {}

    // Clone Method
    Prototype* clone() const override
    {
        return new ConcretePrototype1(*this);
    }

    //void printInfo() const override
    //{
    //    std::cout << info << std::endl;
    //}
};

// Concrete Prototype Class 2
class ConcretePrototype2 : public Prototype
{
private:
    std::string info;
public:
    ConcretePrototype2(const std::string& info) : info(info) {}

    // Clone Method
    Prototype* clone() const override
    {
        return new ConcretePrototype2(*this);
    }

    //void printInfo() const override
    //{
    //    std::cout << info << std::endl;
    //}
};

Client (예시)

int main()
{
    ConcretePrototype1 Proto1("Proto1");
    ConcretePrototype2 Proto2("Proto2");

    Prototype* Clone1 = Proto1.clone(); // ConcretePrototype이 아니라
    Prototype* Clone2 = Proto2.clone(); // Prototype으로 모두 복사가 가능하다

    //Clone1->printInfo();
    //Clone2->printInfo();

    ...
}

장점

  • 클래스에 결합하지 않고도 복제가 가능하다.
  • 초기화 비용이 절감된다.
  • 복잡한 객체를 쉽게 생성할 수 있다.

단점

  • 순환 참조가 있는 복잡한 객체는 조심해야 한다.

 

 

디자인 패턴 (Design Patterns) - Index