Template Method Pattern
템플릿 메소드 패턴이란 객체의 연산에는 알고리즘의 뼈대만 정의하고 각 단계에서 수행할 구체적 처리는 서브클래스쪽으로 미루는 패턴이다. 이를 통해 알고리즘의 구조 자체는 그대로 놔둔 채 알고리즘 각 단계의 처리를 서브클래스에서 재정의할 수 있게 한다.
활용성
- 어떤 한 알고리즘을 이루는 부분 중 변하지 않는 부분을 한 번 정의해 놓고 다양해질 수 있는 부분은 서브클래스에서 정의할 수 있도록 해야할 때
- 서브 클래스 사이의 공통적인 행동을 추출하여 공통 클래스에 몰아둠으로써 코드 중복을 피하고 싶을 때
템플릿 메소드 패턴 사용에 따른 결과
서브클래스의 확장 제어
공통 클래스에 훅메소드를 통해 서브 클래스가 어떤 특정한 시점에 해당 훅 연산을 호출하도록 정의함으로써 특정 시점에만 확장할 수 있도록 제어할 수 있다.
코드 재사용
공통되는 코드를 공통 클래스에 명시한 후 달라지는 부분을 서브클래스에 명시함으로 써 코드의 재사용이 가능해진다.
연산의 특성 명시
공통 클래스를 정의할 때 해당 함수가 공통으로 구현해야 하는 추상 연산인지 상황에 따라 구현해야 하는 훅 연산인지 구분해 두어야 한다.
템플릿 메소드
구조
템플릿 메소드의 구조는 다음과 같다.
C++ 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void TemplateMethodPattern::TemplateMethodPattern() { getCoffee(); getTea(); }
void TemplateMethodPattern::getCoffee() { Drinks* coffee = new Coffee(); coffee->prepareDrinks(); }
void TemplateMethodPattern::getTea() { Drinks* tea = new Tea(); tea->prepareDrinks(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Drinks { void boilWater() { std::cout<<"Boiling Water..."<<std::endl; }
virtual void brew() = 0;
void pouringDrinks() { std::cout<<"Pouring Drinks..."<<std::endl; }
virtual bool needExtraToppings() { return false; }
virtual void addExtraToppings() {}
virtual void preparedDrink() = 0; public: ~Drinks() {}
void prepareDrinks() { boilWater(); brew(); pouringDrinks(); if(needExtraToppings()) addExtraToppings(); preparedDrink(); } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Coffee : public Drinks { void brew() override { std::cout<<"Brewing Coffee Beans..."<<std::endl; }
bool needExtraToppings() { std::cout<<"Need Extra Toppings?"<<std::endl; std::string input = getInput(); return input == "YES"; }
void addExtraToppings() { std::cout<<"Add Some Milk..."<<std::endl; }
std::string getInput() { std::string input; std::cin>>input; return input; }
void preparedDrink() override { std::cout<<"Your Coffee is Ready!!"<<std::endl<<std::endl; } };
|
1 2 3 4 5 6 7 8 9 10 11 12
| class Tea : public Drinks { void brew() override { std::cout<<"Brewing Tea..."<<std::endl; }
void preparedDrink() override { std::cout<<"Your Tea is Ready!!"<<std::endl<<std::endl; } };
|
java 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Client { public static void main(String[] args) { getCoffee(); getTea(); }
private static void getCoffee() { Drinks coffee = new Coffee(); coffee.prepareDrinks(); }
private static void getTea() { Drinks tea = new Tea(); tea.prepareDrinks(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public abstract class Drinks { public final void prepareDrinks() { boilWater(); brew(); pouringDrinks(); if(needExtraToppings()) addExtraToppings(); preparedDrink(); }
private void boilWater() { System.out.println("Boiling Water..."); }
protected abstract void brew();
private final void pouringDrinks() { System.out.println("Pouring Drinks..."); }
protected boolean needExtraToppings() { return false; }
protected void addExtraToppings() {}
protected abstract void preparedDrink(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class Coffee extends Drinks{ @Override protected void brew() { System.out.println("Brewing Coffee Beans..."); }
@Override protected boolean needExtraToppings() { System.out.println("Need Extra Toppings?"); String input = getInput(); return input.equals("YES"); }
private String getInput() { Scanner scanner = new Scanner(System.in); String input = scanner.next(); return input; }
@Override protected void addExtraToppings() { System.out.println("Add Some Milk..."); }
@Override protected void preparedDrink() { System.out.println("Your Coffee is Ready!!"); } }
|
1 2 3 4 5 6 7 8 9 10 11
| public class Tea extends Drinks{ @Override protected void brew() { System.out.println("Brewing Tea..."); }
@Override protected void preparedDrink() { System.out.println("Your Tea is Ready!!"); } }
|