Template method pattern : 일련의 행동을 체계화 할 때 행동 하나하나에 대한 세부 구현은 목적에 따라 바뀔 수 있는 부분이다. 이런 상황에서 세세한 목적에 따라 서로다른 클래스가 생겨난다면 관리의 차원에서 상당히 문제가 된다. Template method는 'template'이라는 단어가 설명하듯, 뼈대를 제공해주므로서 목적에 따른 세세한 변화를 통일성있게 처리할 수 있다.
여기서 Template는 template<Type>으로 표현하는 template과는 전혀 관계없으며, 단지 '틀'이라는 의미로 사용될 뿐이다. 이 패턴은 비슷한 목적을 위한 알고리즘에 대해 뼈대가 되는 행동들을 정의하고 이들 행동으로 큰 틀을 '함수'로서 제공하는 역할을 한다. 파생된 클래스는 뼈대는 건들지 않고 세부적인 행동만을 구현함으로써 알고리즘의 실체를 완성하게된다.
뼈대 클래스(스켈레톤 클래스)는 추상클래스로 알고리즘에 필요한 행동들을 정의하고, templateMethod()에서 이들을 사용하여 알고리즘의 뼈대를 만든다. 이 함수는 final이고 알고리즘의 틀을 정의하는 메소드라 하여 Template method pattern이라 이름붙여진 것이다.
이렇게 제공된 틀은 ConcreteClass에서 행동을 구현하여 온전한 알고리즘으로 완성된다. 여기에 주목할 만한 부분은, needOpC()라 표현한 훜 메소드(Hook method)이다. 뼈대가 세워진 후에는 구현 클래스로부터 뼈대의 변경이 불가능하므로 자칫 알고리즘의 1추상클래스-1구현클래스 라는 비효율적인 구조를 가질 수 있다. 이러한 상황을 막기위해 override 가능한 훅 함수를 두어 알고리즘에 유연성을 더하여 준다.
이런식의 뼈대 구조는 Builder pattern과는 다른 양상을 보인다. Builder는 조합된 인스턴스의 생성루틴이 추상메소드로 제공되어 파생되는 클래스에서 그 구조를 결정하게 된다. 반면 Template method pattern은 미리 정해져 있는 뼈대로부터 세부 구현만이 변경가능하기 때문에 추상클래스로부터 유사한 형태의 결과를 쉽게 예상할 수 있다.
하지만 기반클래스는 요구사항에 따라 언제나 무너질 가능성을 품고있다는 점에서, Template method pattern의 적용은 조심히 이루어 져야 한다. 고려하지 못한 변화에 대처하려다 보면 뼈대가 완전히 바뀌어버릴수도 있는것이다.
이 패턴은 '레시피'혹은 '공정' 이라 나타낼 수 있는 알고리즘의 구현에 적용하면 좋다. 예를들어 빵을 만드는 레시피라면
1. 밀가루에 물을 넣고 반죽한다.
2. 반죽을 숙성시킨다
3. 버터를 바른다
4. 굽는다
와 같이 나타낼 수 있을것이다. 이를 뼈대로 Baking 스켈레톤 클래스를 만들고, 빵의 종류에 따라 각 과정을 세세하게 구현할 수 있다.
public abstract class Baker{
public final Bread bakeBread(){
Ingredient ingredients = putFlour();
ingredients.add( putWater() );
dough( ingredients );
if( needFilling() ){
ingredients.add( putFilling() );
}
ingredients.add( putButter() );
return bake( result );
}
public abstract Ingredient putFlour();
public abstract Ingredient putWater();
public abstract void dough(Ingredient ingredient);
public abstract Ingredient putFilling();
public abstract Ingredient putButter();
public abstract Bread bake(Ingredient ingredient);
public boolean needFilling(){ return true; }
}
public class BaguetteBaker extends Baker{
public Ingredient putFlour(){ return new Flout(); }
public Ingredient putWater(){ return new Water(); }
public void dough(Ingredient ingredient){
ingredient.dough(3.0f); //3분간 반죽
}
public Ingredient putFilling(){ return null; }
public Ingredient putButter(){ return new Butter(); }
public Bread bake(Ingredient ingredient){
return ingredient.bake(10.0f); //10분간 굽기
}
@Override
public boolean needFilling(){ return false; } //속재료는 없음
}
눈에 보이듯, 획기적인 방법으로 빵을 반죽안하고 굽게되었다면, 뼈대가 타격을 받는 상황에 봉착한다. 하지만 큰 그림으로 알고리즘을 표현하기 때문에 코드의 가독성과 확장성에서는 뛰어난 효과를 볼 수 있다.
한줄요약 : 뛰어난 작품을 만들기 전에는 큰 밑그림을 그리기 마련이다.
'Coding Note' 카테고리의 다른 글
[Design pattern] 디자인 패턴이란 (6) | 2013.03.28 |
---|---|
[Design pattern] Visitor (0) | 2013.03.27 |
[Design pattern] Memento (0) | 2013.03.26 |
[Design pattern] Mediator (0) | 2013.03.25 |
[Design pattern] Interpreter (0) | 2013.03.18 |