본문 바로가기

SW 설계/Design Pattern

[Design Pattern] Behavior - 템플릿 메소드 패턴 (Template Method Pattern)

728x90

템플렛 메소드 패턴은 동일한 결과성을 위한 알고리즘을 수행하는 Framework 을 구성할 때 주로 사용되는 패턴으로, 해당 행위가 하위 클래스에서도 구조체를 가진채로 구현되도록 하기 위한 디자인 패턴이다. A single abstracti implementation of an algorithm 을 생성하기 위해 사용되며, 상속 대상 클래스들끼리 유사한 행위로 묶일 수 있을 때 사용된다. 다음과 같은 Coffee 를 만드는 Class 가 있다고 해보자. 

 

 

class Coffee {

    void prepareRecipe() {
        boilWater();
        brewCoffeeGrinds();
        pourInCup();
        addSugarAndMilk();
    }
    
    public void boilWater(){
        // ...
    }
    
    // ...
}

 

 

이번에는 유사하게 Tea 를 만드는 Class 도 필요하다고 해보자. 

 

 

class LemonTea {

    void prepareRecipe() {
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }
    
    public void boilWater(){
        // ...
    }
    
    // ...
}



두 클래스에서는 유사한 행위 및 구조적인 모습을 발견할 수 있다. boilWater 와 pourInCup() 함수는 중복된다고 볼 수 있으며, 종류는 다르지만 음료라는 결과를 위해 유사한 sequential 한 알고리즘이 수행된다는 것을 알 수 있다. 만약 다른 음료까지 추가한다고 하면, 똑같은 함수들을 지속적으로 생성해줘야 한다. 다음과 같은 형태로 변경해보자. 

 

 

public abstract class CaffeineBeverage {

    // 이 골격은 유지하고 싶고, 세부 Step 들은 override 가능하게 해준다
    // 일부는 필수 impl 로 두고, 일부는 기본 구현을 제공하기도 한다
    final void prepareRecipe(){ // 하위 함수들이 Override 할 수 없는 불변하는 함수
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }
    
    abstract void brew(); // brew, addCondiments 하는 방법은 각 하위 함수들마다 다름을 제공
    abstract void addCondiments();
    
    public void boilWater(){
        // ...
    }
    
    public void pourInCup(){
       // ...
    }
    
}



위와 같이 설계된다면 Coffee extends CaffeineBeverage, Tea extends CaffeineBeverage 라는 하위 함수들을 만든 뒤에 brew() 와 addCondiments() 를 Override 하게 지정할 수 있다. 그리고 해당 클래스에서 prepareRecipe() 함수를 수행하면 원하는 결과를 수행할 수 있다. 

 

 

위와 같이 해준다면 CaffeineBeverage 라는 상위의 단일 클래스가 특정 수행 알고리즘을 보호하고 제어할 권한을 가지게 된다. 또한 알고리즘 변화 필요시 해당 클래스만 변경되면 쉽게 유지 보수가 가능하고, 다른 음료들 또한 쉽게 추가될 수 있다는 장점을 가지고 있다. 

 

 

Template Method 패턴에서 final 같이 알고리즘의 Skeleton 을 보호하는 함수를 Template Method (위 예시에서 prepareRecipe()) 라고 하며, 동일한 목적을 수행하는 알고리즘의 골격을 제안한다. 

 

 

Template Pattern 의 Class Diagram 구조

 

 

 

The template pattern defines the steps of an algorithm and allows the subclasses to implement one or more of the steps

 

 

참고로 Template Method Pattern 은  클래스들간의 관계인 inheritance 만을 가지고 정의를 할 수 있고, Object 관련된 내용은 등장하지 않는 것을 알 수 있다. 따라서 Template Method Pattern 은 Class Cope 의 패턴임을 알 수 있다. 

 

 

Template Pattern 은 Strategy Pattern 과 유사하게 특정 알고리즘의 변형 및 variation 을 지원한다고 할 수 있지만, 그 방법이 다르다. Strategy 패턴에서는 알고리즘 전체를 바꾸어서 끼는, interface 단위 자체를 바꾸는 방식이였지만, Template 패턴은 알고리즘 뼈대는 유지하되, 일부 flow 를 바꾸는 상황에서 사용된다. 또한, Template Pattern 이 특수한 상황에 특화된 형태가 바로 Factory Pattern 이다. 

 

 

 

특정 수행 알고리즘을 각자 조금씩 다른 방향으로 진행한다

 

 

 

 

참고) Hook Method

 

Template Method Pattern 과 관련 개념으로, 상황에 따라 기본값 / 혹은 아무 것도 제공하지 않은 상태로 abstract class 에 제공해주는 함수를 말한다. 하위 클래스들이 template 알고리즘에 "hook into" 해서 제어 가능하도록 설계된 부분을 제어할 수 있는 것이다 .

 

 

// ... CaffeineBeverage

final void prepareRecipe(){
    // ...
    if(customerWantsCondiments()) addCondiments();
}

// ...

boolean customerWantsCondiments(){
    return true;
}

 

 

위와 같은 형식으로 addCondiments() 에 hook 함수인 customerWantsCondiments() 를 제공해서, 제공되는 상황에 따른 제어를 추가할 수 있다 (makeBeverage(false) 이런식으로 요청이 올게 할 수 있는 부분). JAVA API 에서도 많이 사용되는 것이 Hook 함수이다. 

 

 

Hook 함수는 High Level Component 가 Low Level Component 에 개입의 여지를 줄 때만, 호출할 때만 호출될 수 있도록 하는 Hollywood Principle 디자인 원리에 대표적인 상황이다. 하위 클래스들은 는 자신이 원할 때 상위 클래스의 Template Method 의 흐름에 개입할 수 없기 때문이다.

 

 

 

출처

 

 

1) 에릭 프리먼, Head First Design Patterns』, O'Reilly Media (2004)

 

 

2) 중앙대학교 소프트웨어학부 이찬근 교수님 디자인 패턴 수업자료 중

728x90