템플릿 메서드 패턴에서는 메서드에서 알고리즘의 골격(템플릿)을 정의한다. 알고리즘의 여러 단계 중 일부는 서브클래스에서 구현할 수 있다. 템플릿 메서드를 이용하면 알고리즘의 구조는 그대로 유지하면서 서브 클래스에서 특정 단계를 재정의할 수 있다.
다시 말해 이 패턴은 알고리즘의 틀을 만들기 위해 사용한다. 틀이란 일련의 단계들로 알고리즘을 정의한 메서드이다. 여러 단계 가운데 하나 이상이 추상 메서드로 정의되며, 그 추상 메서드는 서브클래스에서 구현된다. 이렇게 하면 서브클래스에서 일부분을 구현할 수 있으면서도, 알고리즘의 구조는 바꾸지 않을 수 있다.
<카페의 바리스타 메뉴얼>
커피 만드는 법
1) 물을 끓인다.
2) 커피를 우린다.
3) 컵에 따른다.
4) 설탕과 우유를 추가한다.
홍차 만드는 법
1) 물을 끓인다.
2) 차를 우린다.
3) 컵에 따른다.
4) 레몬을 추가한다.
// 커피 클래스
public class Coffee {
void prepareRecipe(){
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}
public void boilWater(){
System.out.println("물을 끓입니다.");
}
public void brewCoffeeGrinds(){
System.out.println("커피를 우립니다.");
}
public void pourInCup(){
System.out.println("컵에 따릅니다.");
}
public void addSugarAndMilk(){
System.out.println("설탕과 우유를 추가합니다.");
}
}
// 홍차 클래스
public class Tea {
void prepareRecipe(){
boilWater();
steepTeaBag();
pourInCup();
addLemon();
}
public void boilWater() {
System.out.println("물을 끓입니다.");
}
public void steepTeaBag() {
System.out.println("차를 우려냅니다.");
}
public void pourInCup() {
System.out.println("컵에 따릅니다.");
}
public void addLemon() {
System.out.println("레몬을 추가합니다.");
}
}
추상클래스를 추가하여, boilwater, pourInCup 같은 중복되는 코드를 상위로 올린다.
public abstract class CaffeineBeverage {
// 공통적인 부분은 추상클래스로 추출.
abstract void prepareRecipe();
public void boilWater(){
System.out.println("물을 끓입니다.");
}
public void pourInCup(){
System.out.println("컵에 따릅니다.");
}
}
public class Coffee extends CaffeineBeverage{
void prepareRecipe(){
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}
// 코드 중복 제거
// public void boilWater(){
// System.out.println("물을 끓입니다.");
//}
//public void pourInCup(){
// System.out.println("컵에 따릅니다.");
//}
public void brewCoffeeGrinds(){
System.out.println("커피를 우립니다.");
}
public void addSugarAndMilk(){
System.out.println("설탕과 우유를 추가합니다.");
}
}
public class Tea extends CaffeineBeverage{
void prepareRecipe(){
boilWater();
steepTeaBag();
pourInCup();
addLemon();
}
// 코드 중복 제거
//public void boilWater() {
// System.out.println("물을 끓입니다.");
//}
//public void pourInCup() {
// System.out.println("컵에 따릅니다.");
//}
public void steepTeaBag() {
System.out.println("차를 우려냅니다.");
}
public void addLemon() {
System.out.println("레몬을 추가합니다.");
}
}
public abstract class CaffeineBeverage {
// 공통적인 부분은 추상클래스로 추출.
// 새로 생긴 의문점 -> prepareRecipe() 메서드도 추상화시킬 수 있지 않을까?
// abstract void prepareRecipe();
// template method 패턴 적용하기
/**
* 템플릿 메서드. 어떤 알고리즘에 대한 템플릿 역할을 한다.
* 이 경우에는 카페인이 들어있는 음료를 만들기 위한 알고리즘의 템플릿이다.
* 1) 탬플릿 내에서 각 단계는 메서드로 표현된다.
* 2) 어떤 메서드는 이 클래스 내에서 구현된다. 어떤 서브클래스든 동일한 작동을 보이는 기능은 추상 클래스에서 정의.
* 3) 어떤 메서드는 서브클래스에서 구현된다. 서브클래스에서 구현할 메서드는 abstract로 클래스 내부에서 선언.
*/
final void prepareRecipe(){ // 상속받는 클래스에서 순서를 변경할 수 없게 final로 선언
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
public void boilWater(){
System.out.println("물을 끓입니다.");
}
public void pourInCup(){
System.out.println("컵에 따릅니다.");
}
}
public class Coffee extends CaffeineBeverage {
@Override
public void brew(){
System.out.println("커피를 우립니다.");
}
@Override
void addCondiments() {
System.out.println("설탕과 우유를 추가합니다.");
}
}
public class Tea extends CaffeineBeverage {
@Override
void brew() {
System.out.println("차를 우려냅니다.");
}
@Override
void addCondiments() {
System.out.println("레몬을 추가합니다.");
}
}