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

 

Coffe Tea만들기

커피와 차를 만드는 방법은 비슷할 것이다. 이것에 대한 공통 부분을 인식하여 추상클래스로 만들고 나면 다음과 같을 것이다.

 

하지만

ü  커피의 끓는 물에 커피를 우려내는 것( brewCoffeeGrinds() ) ßà 차를 우려내는것( steepTeaBa() )

ü  설탕과 우유를 추가하는 것( addSugarAndMilk() ) ß à 레몬을 추가하는것( addLemon() )

 

위의 행위들은 다르지만 비슷하다. 이러한 행위들까지 공통으로 묶어서 상위 클래스로 옮기면서 추상 메소드로 정의하여 하위 클래스에서 각자 다시 구현하게 하는것이 올바르다.

 

그리고 커피와 차만드는 공정을 하나의 틀로 묶어(Template Method) 설계한다.

 

 

다음 코드은CaffeineBeverage 구현하면서 템플릿 메소드( prepareRecipe() ) 구현한 예이다.

 

 

package headfirst.templatemethod.barista;

 

public abstract class CaffeineBeverage {

 

       // 서브클래스에서 Override할수 없도록 final 선언한다.

       final void prepareRecipe() {            

boilWater();

brew();

                           pourInCup();

addCondiments();

       }

 

       abstract void brew();  

 

       abstract void addCondiments();  

 

       void boilWater() {

              System.out.println("Boiling water");

       }

 

       void pourInCup() {

              System.out.println("Pouring into cup");

       }

}

 

 

 

 

 

후크(hook) 메소드 사용

 

후크가 있으면 메소드를 오버라이드할 수도 있고 그냥 넘어 수도 있다. 이렇게하면 서브클래스 입장에서는 다양한 위치에서 알고리즘에 끼어 들수있다.

 

 

package headfirst.templatemethod.barista;

 

public abstract class CaffeineBeverageWithHook {

 

       void prepareRecipe() {

              boilWater();

              brew();

              pourInCup();

if (customerWantsCondiments()) {

addCondiments();

}

       }

 

       abstract void brew();

 

       abstract void addCondiments();

 

       void boilWater() {

              System.out.println("Boiling water");

       }

 

       void pourInCup() {

              System.out.println("Pouring into cup");

       }

 

       // 후크메소드
       // 서브클래스에서 다양한 목적으로 새로 Override하여 상위 로직에 참여할 있다.

boolean customerWantsCondiments() {

return true;

}

}

 

 

 

다음코드는 서브클래스에서 어떻게 후크 메소드를 사용하는지 보여준다.

 

package headfirst.templatemethod.barista;

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

 

public class CoffeeWithHook extends CaffeineBeverageWithHook {

 

       public void brew() {

              System.out.println("Dripping Coffee through filter");

       }

 

       public void addCondiments() {

              System.out.println("Adding Sugar and Milk");

       }

 

       /* 서브클래스에서 새로 정의하여 상위 로직에 참여한다.

        * @see headfirst.templatemethod.barista.CaffeineBeverageWithHook#customerWantsCondiments()

        */

       @Override

public boolean customerWantsCondiments() {

String answer = getUserInput();

if (answer.toLowerCase().startsWith("y")) {

              return true;

} else {

       return true

}

}

 

       private String getUserInput() {

              String answer = null;

              System.out.print("Would you like milk and sugar with your coffee (y/n)? ");

 

              BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

              try {

                     answer = in.readLine();

              } catch (IOException ioe) {

                     System.err.println("IO error trying to read your answer");

              }

              if (answer == null) {

                     return "no";

              }

              return answer;

       }

}

 

 

 

BeverageTestDrive.java

CaffeineBeverage.java

CaffeineBeverageWithHook.java

Coffee.java

CoffeeWithHook.java

Tea.java

TeaWithHook.java


'Java Design Pattern' 카테고리의 다른 글

State 패턴  (0) 2013.02.22
Iterator 패턴 & Composite 패턴  (0) 2013.02.21
Factory 패턴  (0) 2013.02.20
Decorator 패턴  (0) 2013.02.20
Observer 패턴  (0) 2013.02.20
Posted by Steven J.S Min
,