참고: JAVA 언어로 배우는 디자인 패턴 입문
Templete Method 패턴은 상위 클래스쪽에 템플릿에 해당하는 메소드가 정의되어 있고, 그 메소드의 정의 안에는 추상 메소드가 사용되고 있습니다. 따라서 상위 클래스의 프로그램만 보면 추상 메소드를 어떻게 호출하고 있는지 알 수 있지만, 최종적으로 어떤 처리가 수행되는지는 알 수 없습니다.
추상 메소드를 실제로 구현하는 것은 하위 클래스입니다. 하위 클래스 측에서 메소드를 구현하면 구체적인 처리가 결정됩니다. 서로 다른 하위 클래스가 서로 다른 구현을 실행하면 서로 다른 처리가 실행될 것입니다. 그러나 어떤 하위 클래스에서 어떤 구현을 하더라도 처리의 큰 흐름은 상위 클래스에서 결정한대로 이루어집니다. 이와 같이 상위 클래스에서의 뼈대를 결정하고, 하위 클래스에서 그 구체적인 내용을 결정하는 패턴을 Templete Method 패턴 이라고 합니다.
public abstract class AbstractDisplay {
public abstract void open(); // 하위 클래스에 구현을 맡기는 추상 메소드 (1) open
public abstract void print(); // 하위 클래스에 구현을 맡기는 추상 메소드 (2) print
public abstract void close(); // 하위 클래스에 구현을 맡기는 추상 메소드 (3) close
public final void display() { // 추상 클래스에서 구현되고 있는 메소드 display
open(); // 우선 open하고..
for(int i = 0; i < 5> print();
}
close(); // 마지막으로 close한다. 이것이 display 메소드에서 구현되고 있는 내용.
}
}
public class CharDisplay extends AbstractDisplay {
private char ch; // 표시해야 할 문자
public CharDisplay(char ch) { // 생성자에게 전달된 문자 ch를
this.ch = ch;
}
@Override
public void open() {
System.out.println("<<");
}
@Override
public void print() {
System.out.println(ch);
}
@Override
public void close() {
System.out.println(">>");
}
}
public class Main {
public static void main(String[] args) {
// 'H'를 가진 CharDisplay 인스턴스 생성
AbstractDisplay d1 = new CharDisplay('H');
// "Hello, World."를 가진 StringDisplay 인스턴스 생성
AbstractDisplay d2 = new StringDisplay("Hello, World.");
// "안녕하세요."를 가진 StringDisplay의 인스턴스 생성
AbstractDisplay d3 = new StringDisplay("안녕하세요.");
/*
* d1, d2, d3 모두 같은 AbstractDisplay의 하위 클래스의 인스턴스이기 때문에
* 상속한 display 메소드를 호출할 수 있음
* 실제 동작은 CharDisplay나 StringDisplay에서 결정함
*/
d1.display();
d2.display();
d3.display();
}
}
Q. Template Method 패턴을 사용하면 어떤 이점이 있을까요?
상위 클래스의 템플릿 메소드에서 알고리즘이 기술되어 있으므로, 하위 클래스측에서는 알고리즘을 일일이 기술할 필요가 없습니다. 예를 들어 Template Method 패턴을 사용하지 않고, 에디터의 복사 & 붙여넣기 기능을 사용해서 복수의 ConcreteClass 역할을 만들었다고 가정합니다.
ConcreteClass1, ConcreteClass2, ConcreteClass3... 은 모두 비슷하지만 다른 클래스가 됩니다. 작성한 후에는 괜찮지만 나중에 ConcreteClass1에 버그가 발견되면 대체 어떻게 될까요? 1개의 버그를 수정하기 위해 모든 ConcreteClass를 수정해야 됩니다. 그런 점에서 Template Method 패턴으로 프로그래밍을 하면 템플릿 메소드에 오류가 발견되더라도 템플릿 메소드만 수정하면 됩니다.
[추가]
- CharDisplay의 인스턴스도, StringDisplay의 인스턴스도 AbstractDisplay 타입의 변수에 대입하고 있습니다. 그리고 display()를 호출하고 있습니다.
'상위 클래스 타입의 변수에 하위 클래스의 어떠한 인스턴스를 대입해도 제대로 작동할 수 있도록 한다.' 의 원칙을 LSP(The Liskov Substitution Principle) 라고 합니다. (상속의 일반적인 원칙)
- Template Method 패턴에서는 처리의 골격을 상위 클래스에서 기술하고 구체적인 내용은 하위 클래스에서 수행하고 있습니다. 어느 레벨에서 처리를 분배할지, 어떤 처리를 상위 클래스에 두고 어떤 처리를 하위 클래스에 둘 것인지를 정한 매뉴얼은 없습니다. 그것은 프로그램을 설계하는 사람의 몫입니다.