템플릿 메소드(Template Method) 패턴
템플릿 메소드 패턴은 상위 클래스에 알고리즘의 골격의 정의하고 알고리즘의 일부 구현을 하위 클래스에 위임하여 알고리즘을 재사용할 수 있도록 하는 패턴을 말한다.
템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브클래스에서 구현할 수 있으며, 알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브클래스에서 재정의할 수 있다.
템플릿 메소드 패턴을 사용하면 부모 클래스에서 알고리즘의 골격을 제공하기 때문에 추후 알고리즘에 변경이 일어나더라도 부모 클래스 한 군데만 수정하면 된다는 장점이 있다.
예시
템플릿 메소드 패턴이 어떻게 구현되는지 예시로 확인해보자.
아래 Tea
클래스는 추상 클래스로 make()
메서드에서 알고리즘의 골격을 정의한다.
make()
메서드는 내부에서 여러 메서드를 호출하는데, 이 중 일부는 추상 메서드이기 때문에 Tea
를 상속한 하위 클래스에서 구현해야 한다.
Tea
의 make()
메서드는 알고리즘을 이루는 메서드들이 언제 어떤 흐름으로 호출될 지 정의해둔 것으로 프레임워크로 볼 수 있다.
public abstract class Tea {
private String teaName;
public Tea(String teaName) {
this.teaName = teaName;
}
public final void make() {
System.out.println("tea '" + teaName + "' make start");
prepare();
boil();
if (hasAdditional()) {
addCondiment();
}
complete();
System.out.println("tea '" + teaName + "' make end");
}
protected abstract void prepare();
private void boil() {
System.out.println("물 끓이기");
}
protected boolean hasAdditional() {
return false;
}
protected abstract void addCondiment();
protected abstract void complete();
}
아래는 Tea
클래스를 상속받은 SimpleTea
클래스이다.
Tea
클래스에서 추상 메서드로 정의한 메서드들을 여기서 구현한다.
SimpleTea
는 추상 메서드를 간단하게 구현했다.
public class SimpleTea extends Tea {
public SimpleTea(String teaName) {
super(teaName);
}
@Override
protected void prepare() {
System.out.println("[SimpleTea] prepare");
}
@Override
protected void addCondiment() {}
@Override
protected void complete() {
System.out.println("[SimpleTea] No condiments SimpleTea Complete");
}
}
아래는 Tea
클래스를 상속받은 CustomTea
클래스이다.
CustomTea
는 SimpleTea
와 다르게 사용자로부터 첨가물을 입력받아 complete()
메서드에서 입력받은 내용을 출력한다.
또한 hasAdditional()
메서드는 추상 메서드는 아니지만, 오버라이딩해서 첨가물을 입력받을 수 있도록 했다.
public class CustomTea extends Tea {
private String condiments;
public CustomTea(String teaName) {
super(teaName);
}
@Override
protected void prepare() {
System.out.println("[CustomTea] prepare");
}
@Override
protected boolean hasAdditional() {
return true;
}
@Override
protected void addCondiment() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("[CustomTea] 첨가물을 입력하세요.");
System.out.println("[CustomTea] 아래 중 한가지를 선택해서 번호를 입력해주세요.");
System.out.println("[CustomTea] 0. 추가 안함");
System.out.println("[CustomTea] 1. 포도");
System.out.println("[CustomTea] 2. 레몬");
System.out.println("[CustomTea] 3. 자몽");
try {
int num = Integer.parseInt(br.readLine());
switch (num) {
case 0:
break;
case 1:
this.condiments = "포도";
break;
case 2:
this.condiments = "레몬";
break;
case 3:
this.condiments = "자몽";
break;
default:
throw new RuntimeException("입력 오류 발생");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void complete() {
StringBuffer sb = new StringBuffer();
sb.append("[CustomTea] ");
if (this.condiments == null) {
sb.append("No condiments CustomTea Complete");
} else {
sb.append("Condiments name ");
sb.append("'").append(condiments).append("' CustomTea Complete");
}
System.out.println(sb);
}
}
추상 클래스를 상속받은 SimpleTea
와 CustomTea
를 구현했으므로 이를 생성하여 사용해보자.
public class Main {
public static void main(String[] args) {
List<Tea> teas = new ArrayList<>();
teas.add(new SimpleTea("단순 티"));
teas.add(new CustomTea("커스텀 티"));
for (Tea tea : teas) {
System.out.println("=======================");
tea.make();
}
}
}
다음과 같은 출력을 확인할 수 있다.
=======================
tea '단순 티' make start
[SimpleTea] prepare
물 끓이기
[SimpleTea] No condiments SimpleTea Complete
tea '단순 티' make end
=======================
tea '커스텀 티' make start
[CustomTea] prepare
물 끓이기
[CustomTea] 첨가물을 입력하세요.
[CustomTea] 아래 중 한가지를 선택해서 번호를 입력해주세요.
[CustomTea] 0. 추가 안함
[CustomTea] 1. 포도
[CustomTea] 2. 레몬
[CustomTea] 3. 자몽
2
[CustomTea] Condiments name '레몬' CustomTea Complete
tea '커스텀 티' make end
Process finished with exit code 0
결론
위 예시와 같이 템플릿 메소드 패턴을 직접 구현해보았다.
알고리즘의 전체적인 흐름을 정의한 메서드를 작성하고, 전체 알고리즘을 세부적으로 나눈 추상 메서드를 상위 클래스(Tea
)에 선언하여 알고리즘의 흐름을 한 곳에서 관리할 수 있도록 하였다.
확실히 알고리즘의 흐름을 수정할 필요가 있다면 Tea
만 수정하면 되기 때문에 편리해보인다.
Tea
의 추상 메서드들을 구현한 하위 클래스 SimpleTea
와 CustomTea
에서 각각 서로에게 맞는 알고리즘의 내부 구현을 작성할 수 있었고, 필요에 따라 Tea
에 기본으로 정의된 메서드를 오버라이딩하여(Tea
의 hasAdditional()
메서드) Tea
에 작성된 알고리즘의 흐름을 프레임워크가 지원하는 내에서 변경할 수 있었다.
템플릿 메소드 패턴의 특징과 장점을 잘 활용해보자.