어떤 작업을 처리하는 일부분을 서브 클래스로 캡슐화해 전체 일을 수행하는 구조는 바꾸지 않으면서 특정 단계에서 수행하는 내역을 바꾸는 패턴이다.
일반적으로 상위 클래스(추상 클래스)에는 추상 메서드를 통해 기능의 골격을 제공하고, 하위 클래스(구체 클래스)의 메서드에는 세부 처리를 구체화하는 방식으로 사용하며 코드 양을 줄이고 유지보수를 용이하게 만드는 특징을 갖는 패턴이다.
즉, 여러 클래스에서 공통으로 사용하는 메서드를 템플릿화 하여 상위 클래스에서 정의하고, 하위 클래스마다 세부 동작 사항을 다르게 구현하는 패턴이라고 볼 수 있다.
- AbstractClass(추상 클래스) : 템플릿 메소드를 구현하고, 템플릿 메소드에서 돌아가는 추상 메소드를 선언한다. 이 추상 메소드는 하위 클래스인 ConcreteClass 역할에 의해 구현된다.
- ConcreteClass(구현 클래스) : AbstractClass를 상속하고 추상 메소드를 구체적으로 구현한다. ConcreteClass에서 구현한 메소드는 AbstractClass의 템플릿 메소드에서 호출된다.
훅(hook) 메소드는 부모의 템플릿 메서드의 영향이나 순서를 제어하고 싶을때 사용되는 메서드 형태를 말한다.
예를 들어, 템플릿 메서드 내에 실행되는 동작을 hook1() 이라는 메서드의 참, 거짓 유무에 따라 다음 스텝을 어떻게 이어나갈지 지정한다. 이를 통해 자식 클래스에서 좀더 유연하게 템플릿 메서드의 알고리즘 로직을 다양화 할 수 있다는 특징이 있다.
훅 메소드는 추상 메소드가 아닌 일반 메소드로 구현하는데, 선택적으로 오버라이드 하여 자식 클래스에서 제어하거나 아니면 놔두거나 하기 위해서 이다.
// Teacher.java (AbstractClass)
public abstract class Teacher {
public final void startClass() {
enterClassroom();
teach();
leaveClassroom();
}
public void enterClassroom() {
System.out.println("[Teacher] enters classroom...");
}
public void leaveClassroom() {
System.out.println("[Teacher] leaves classroom...");
}
abstract void teach();
}
// EnglishTeacher.java (ConcreteClass)
public class EnglishTeacher extends Teacher {
@Override
public void teach() {
System.out.println("[EnglishTeacher] teaches English...");
}
}
// MathTeacher.java (ConcreteClass)
public class MathTeacher extends Teacher {
@Override
public void teach() {
System.out.println("[MathTeacher] teaches Mathematics...");
}
}
// Client.java (Client)
public class Client{
public static void main(String[] args) {
Teacher engTeacher = new EnglishTeacher();
Teacher mathTeacher = new MathTeacher();
engTeacher.startClass();
mathTeacher.startClass();
}
}
// 실행 결과
[Teacher] enters classroom...
[EnglishTeacher] teaches English...
[Teacher] leaves classroom...
[Teacher] enters classroom...
[MathTeacher] teaches Mathematics...
[Teacher] leaves classroom...
우선 추상클래스로 Teacher를 정의해주고 일련의 처리 과정을 정의 및 구현한다. 그 중 구체 클래스에 따라 다르게 처리되는 메소드만 abstract로 정의하여 자식 클래스에서 세부적으로 구현할 수 있게 남겨두고, 정의된 메소드들을 처리 흐름에 따라 처리하는 메소드(Template Method)를 구현한다. Client는 템플릿 메소드를 호출하여 일련의 프로세스를 수행한다.
만약 구체들이 공통적으로 특정 기능을 수행하는데 하나의 구체 클래스가 다른 방식으로 해당 기능을 수행한다면 다음과 같이 오버라이딩하여 재정의 해줄수 있다.
예를 들어, 국어 선생님은 수업이 끝나도 교실을 떠나지 않고 계속 반에 머물러 있는 특성이 있다고 가정해보자.
// KoreanTeacher.java (ConcreteClass)
public class KoreanTeacher extends Teacher {
@Override
public void leaveClassroom() {
System.out.println("[KoreanTeacher] I don't wanna leave, I am staying here,,, ");
}
@Override
public void teach() {
System.out.println("[KoreanTeacher] teaches Korean...");
}
}
// Client.java
public class Client{
public static void main(String[] args) {
Teacher engTeacher = new EnglishTeacher();
Teacher mathTeacher = new MathTeacher();
Teacher korTeacher = new KoreanTeacher();
korTeacher.startClass();
engTeacher.startClass();
mathTeacher.startClass();
}
}
// 실행 결과
[Teacher] enters classroom...
[KoreanTeacher] teaches Korean...
[KoreanTeacher] I don't wanna leave, I am staying here,,,
[Teacher] enters classroom...
[EnglishTeacher] teaches English...
[Teacher] leaves classroom...
[Teacher] enters classroom...
[MathTeacher] teaches Mathematics...
[Teacher] leaves classroom...
국어선생님이 교실을 떠나지 않고 남은 두 수업을 참관하게 됬다..
[디자인패턴] 디자인패턴이란? - 생성패턴, 구조패턴, 행위패턴