GoF의 디자인 패턴에 의하면, 템플릿 메소드 패턴이란 알고리즘의 구조를 메소드에 정의하고, 하위 클래스에서 알고리즘 구조의 변경없이 알고리즘을 재정의 하는 패턴이다. 알고리즘이 단계별로 나누어 지거나, 같은 역할을 하는 메소드 이지만 여러곳에서 다른 형태로 사용이 필요한 경우 유용한 패턴이다.
토비의 스프링에 의하면, 템플릿 메소드 패턴이란 상속을 통해 슈퍼클래스의 기능을 확장할 때 사용하는 가장 대표적인 방법. 변하지 않는 기능은 슈퍼클래스에 만들어 두고 자주 변경되며 확장할 기능은 서브클래스에서 만들도록 한다.
만약 두 개의 라면을 끓이는 과정이 아래와 같다고 가정하자.
<신라면>
1. 물을 끓인다.
2. 면을 넣는다.
3. 계란을 넣는다.
4. 4분 기다린다.
<너구리>
1. 물을 끓인다.
2. 면을 넣는다.
3. 콩나물을 넣는다.
4. 5분 기다린다.
public class ShinRamen { // 신라면 조리 방법
public void boilWater() {
System.out.println("물을 끓인다.");
}
public void putNoodles() {
System.out.println("면을 넣는다.");
}
public void putEgg() {
System.out.println("계란을 넣는다.");
}
public void waitForMinutes() {
System.out.println("4분 기다린다.");
}
}
public class RaccoonRamen { // 너구리 조리 방법
public void boilWater() {
System.out.println("물을 끓인다.");
}
public void putNoodles() {
System.out.println("면을 넣는다.");
}
public void putBeanSprouts() {
System.out.println("콩나물을 넣는다.");
}
public void waitForMinutes() {
System.out.println("5분 기다린다.");
}
}
위 두개의 코드에서, 물을 끓이는 것과 면을 넣는 행위는 완전히 동일한 코드이다. 따라서 Ramen이라는 클래스를 정의하여 중복된 코드를 제거할 수 있다. 그리고 추가로 '무언가'를 넣는 행위와 'x분' 기다린다는 행위가 유사하다. 템플릿 메소드 패턴은 이것도 추상화하는것이 목표이다.
public abstract class Ramen { //추상클래스 선언
public final void makeRamen() { // 템플릿 메소드
boilWater();
putNoodles();
putExtra();
waitForMinutes();
}
private void boilWater() {
System.out.println("물을 끓인다.");
}
private void putNoodles() {
System.out.println("면을 넣는다.");
}
protected abstract void putExtra(); // 추상메소드
protected abstract waitForMinutes() // 추상메소드
public void eat() { // 훅 메소드
System.out.println("냄비에 담습니다.");
}
}
public class ShinRamen extends Ramen {
@Override
public void putExtra() {
System.out.println("계란을 넣는다.");
}
@Override
public void waitForMinutes() {
System.out.println("4분 기다린다.");
}
}
public class RaccoonRamen extends Ramen {
@Override
public void putExtra() {
System.out.println("콩나물을 넣는다.");
}
@Override
public void waitForMinutes() {
System.out.println("5분 기다린다.");
}
}