템플릿 메소드 패턴
템플릿 메소드 패턴은 알고리즘의 골격을 정의합니다.
•
템플릿 메소드를 사용하면 알고리즘의 일부 탄계를 서브클래스에서 구현가능
•
알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브클래스에서 재정의 가능
•
후크는 추상 클래스에서 선언되지만 기본적인 내용만 구현되어 있거나 아무 코드도 들어있지 않은 메소드
◦
서브클래스는 다양한 위치에서 알고리즘에 끼어들 수 있음
▪
물론 그냥 무시하고 넘어갈 수 있음
후크 활용하기
후크가 있으면 해당 메소드를 오버라이드 할 수 있고, 그냥 넘어갈 수도 있음
public abstract class CaffeineBeverageWithHook {
final 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");
}
boolean customerWantsCondiments() {
return true;
}
}
Java
복사
public class CoffeeWithHook extends CaffeineBeverageWithHook {
public void brew() {
System.out.println("필터로 커피를 우려내는 중");
}
public void addCondiments() {
System.out.println("우유와 설탕을 추가하는 중");
}
public boolean customerWantsCondiments() {
String answer = getUserInput();
if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
}
private String getUserInput() {
String answer = null;
System.out.print("커피에 우유와 설탕을 넣을까요? (y/n)? ");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
answer = in.readLine();
} catch (IOException ioe) {
System.err.println("IO 오류");
}
if (answer == null) {
return "no";
}
return answer;
}
}
Java
복사
할리우드 원칙
먼저 연락하지 마세요. 저희가 연락 드리겠습니다.
•
할리우드 원칙을 활용하면 의존성 부패를 방지할 수 있음
•
어떤 고수준 구성 요소가 저수준 구성요소에 의존하고, 그 저수준 구성요소는 다시 고수준 구성요소에 의존하고, 그 고수준 구성요소… 무한 반복
◦
의존성이 복잡하게 꼬여 있는 상황을 의존성이 부패했다고 부름
◦
이렇게 의존성이 부패했다면 시스템 디자인이 어떤 식으로 되어 있는지 아무도 알아볼 수 없음
•
저수준 구성요소가 시스템에 접속할 수 있지만 언제, 어떻게 그 구성 요소를 사용하지는 고수준 구성 요소가 결정함
할리우드 원칙과 템플릿 메소드 패턴
스타버즈 카페에서의 예시
커피를 만드는 방법과 홍차를 만드는 방법이 거의 동일함
public class Coffee {
void prepareRecipe() {
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}
public void boilWater() {
System.out.println("Boiling water");
}
public void brewCoffeeGrinds() {
System.out.println("Dripping Coffee through filter");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
public void addSugarAndMilk() {
System.out.println("Adding Sugar and Milk");
}
}
Java
복사
public class Tea {
void prepareRecipe() {
boilWater();
steepTeaBag();
pourInCup();
addLemon();
}
public void boilWater() {
System.out.println("Boiling water");
}
public void steepTeaBag() {
System.out.println("Steeping the tea");
}
public void addLemon() {
System.out.println("Adding Lemon");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}
Java
복사
•
prepareRecipe() 메소드를 통해서 제조법이 동일하다는 사실을 알 수 있음
prepareRecipe 메소드 추상화 하기
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("물 끊이는 중");
}
void pourInCup() {
System.out.println("컵에 따르는 중");
}
}
Java
복사
public class Coffee extends CaffeineBeverage {
public void brew() {
System.out.println("필터로 커피를 우려내는 중");
}
public void addCondiments() {
System.out.println("설탕과 우유를 추가하는 중");
}
}
Java
복사
public class Tea extends CaffeineBeverage {
public void brew() {
System.out.println("찻잎을 우려내는 중");
}
public void addCondiments() {
System.out.println("레몬을 추가하는 중");
}
}
Java
복사
•
물을 끓인다와 만들어진 음료를 겁에 따른다는 동일한 행동이기 때문에 추상화 가능
•
우려내는 행위와 추가하는 행위는 동일하기 때문에 추상화 해서 서브클래스에게 구현을 위임
•
알고리즘이 한 군데 모여있으므로 한 부분만 고치면 됨