TemplateMethod Pattern( 템플릿 메소드 패턴 ) 【 디자인패턴 】

[ TemplateMethod Pattern의 정의 ]
메소드에서 알고리즘의 골격을 정의한다. 알고리즘의 여러 단계중 일부는 서브클래스에서 구현할 수 있다. 템플릿 메소드를 이용하면 알고리즘의 구조는 그대로 유지하면서 서브클래스에서 특정 단계를 재정의할 수 있다.

[ 클래스 다이어그램 ]

[ 시나리오 ]
바리스타가되어 커피와 차를 만들기 위한 클래스를 작성한다. 그런데 커피 클래스와 차 클래스는 공통점이 많고, 중복되는 코드도 생겨나게 된다. 어떻게 하면 추상화시키고 유연하게 확장 할 수 있을까?

[ 디자인 원칙 ]
먼저 연락하지 마세요. 저희가 연락 드리겠습니다. 이것을 "할리우드 원칙(Hollywood Principle)" 이라고 한다.
헐리우드 원칙을 이용하면 "의존성 부패(Dependency rot)"를 방지 할 수 있다.  어떤 고수준 구성요소가 저수준 구성요소에 의존하고, 그 저 수준 구성요소는 다시 고수준 구성요소에 의존하는 것과 같은 식으로 의존성이 복잡하게 꼬여있는 것을 의존성 부패라고 부른다. 헐리우드 원칙을 사용하면, 저수준 구성요소에서는 시스템에 접속할 수 있지만, 언제 어떤 식으로 그 구성요소들을 사용할지는 고수준 구성요소에서 결정하게 된다. 즉 고수준 구성요소에서 저수준 구성요소에게 "연락하지 마세요. 제가 먼저 연락 드리겠습니다." 라고 애기하는 것과 같다.

[ 요약 ]
PrepareRecipe가 템플릿메소드 역할을 하게되고, Brew, AddCondiments는 수순가상함수로 서브클래스에서 재정의하여 사용하게된다. 여기서 한가지 눈여겨볼 것은 Hook라는 가상함수가 존재한다는 것이다. 이는 서브클래스에서 재정의가 있다면 서브클래스의 재정의된 함수가 쓰이고, 재정의가 없는한 추상클래스의 가상함수가 그되로 쓰이게 되는데 후크는 다양한 용도로 사용될 수 있다.

[ 구현코드 ]
#include "stdafx.h"
#include <iostream>
#include <string>

using namespace std;

class CaffeineBeverage
{
public:
    void    PrepareRecipe( void )
    {
        BoilWater();
        Brew();
        PourInCup();
        AddCondiments();
        CustomerWantsHook();
    }

protected:
    virtual void    Brew( void ) = 0;
    virtual void    AddCondiments( void ) = 0;
    virtual bool    CustomerWantsHook( void ) { return true; }

private:
    void    BoilWater( void ) { cout<<"물을 끊이는 중..."<<endl; }
    void    PourInCup( void ) { cout<<"컵에 따르는 중..."<<endl; }
};

class Coffee : public CaffeineBeverage
{
protected:
    virtual void    Brew( void ) { cout<<"필터로 커피를 우려내는 중..."<<endl; }
    virtual void    AddCondiments( void ) { cout<<"우유와 설탕을 추가하는 중..."<<endl; }

    bool    CustomerWantsHook( void )
    {
        Topping();
        return true;
    }

private:
    void    Topping( void ) { cout<<"스팀 우유를 추가하는 중..."<<endl; }
};

class Tea : public CaffeineBeverage
{
protected:
    virtual void    Brew( void ) { cout<<"차를 우려내는 중..."<<endl; }
    virtual void    AddCondiments( void ) { cout<<"레몬을 추가하는 중..."<<endl; }

    bool    CustomerWantsHook( void )
    {
        Box();
        return true;
    }

private:
    void    Box( void ) { cout<<"테이크 아웃 중..."<<endl; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Coffee* pCoffee = new Coffee;
    Tea* pTea = new Tea;

    cout<<"[커피를 주문했어요~]"<<endl;
    pCoffee->PrepareRecipe();
    cout<<endl;

    cout<<"[홍차를 주문했어요~]"<<endl;
    pTea->PrepareRecipe();
    cout<<endl;
}

[ 결과화면 ]

덧글

댓글 입력 영역