템플릿 메서드 패턴 정의
- 부모 클래스에서 알고리즘의 골격을 정의하지만, 해당 알고리즘의 구조를 변경하지 않고 자식
클래스들이 알고리즘의 특정 단계들을 오버라이드(재정의)할 수 있도록 하는 행동 디자인 패턴이다.- 전체적으로는 동일하면서 부분적으로는 다른 구문으로 구성된 메서드의 코드 중복을 최소화할때 유용하다.
- 또한 동일한 기능을 상위 클래스에서 정의하면서 확장/변화가 필요한 부분만 서브 클래스에서 구현할 수 있도록 한다.
예시로 커피와 홍차를 만들때 2개다 물을 끓여야한다고 하면 boiWater을 템플릿 메서드로 정의할 수 있다
장점
- 알고리즘 구조의 재사용성: 템플릿 메서드는 알고리즘의 일반적인 구조를 부모 클래스에 정의하므로, 여러 하위 클래스에서 이 구조를 재사용할 수 있습니다.
- 유연성과 확장성: 부모 클래스에서 정의된 템플릿 메서드를 재정의하여 새로운 알고리즘을 쉽게 추가할 수 있습니다. 이는 새로운 기능을 도입하거나 알고리즘의 일부를 변경할 때 확장성을 제공합니다.
- 코드 중복 최소화: 공통된 부분은 부모 클래스에서 구현되므로 코드 중복을 최소화하고 유지보수를 용이하게 합니다.
- 구현 은닉: 템플릿 메서드는 알고리즘의 구조를 정의하고 세부적인 단계를 서브클래스에 위임하므로, 각 단계의 구현 내용을 숨길 수 있습니다.
단점
- 강제성: 서브클래스에서 반드시 템플릿 메서드의 일부 단계를 구현해야 합니다. 이는 특정한 구조를 강제하기 때문에 자유로운 설계가 어려울 수 있습니다.
- 클래스 수 증가: 많은 수의 템플릿 메서드를 가진 많은 수의 서브클래스가 있다면 클래스의 수가 급격하게 증가할 수 있습니다.
- 유연성 부족: 템플릿 메서드 패턴은 일부 클라이언트 코드에 대한 수정 없이 알고리즘을 변경할 수 있지만, 새로운 알고리즘 전체를 추가하려면 새로운 서브클래스를 만들어야 합니다.
- 재사용 한계: 일부 경우에는 알고리즘의 구조가 고정되어 있기 때문에 재사용이 어려울 수 있습니다.
패턴 적용 이전
이미지화
각 음료는 prepareRecipe()메서드와 각 음료를 만드는데 사용되는 메서드들로 이루어져있다.
코드
Coffe.java
public class Coffee {
//커피 만드는 메서드
void prepareRecipe() {
boilWater();
brewCoffeGrinds();
pourInCup();
addSugarAndMilk();
}
public void boilWater() {
System.out.println("물 끓이는중");
}
public void brewCoffeGrinds() {
System.out.println("필터로 커피를 우려내는중..");
}
public void pourInCup() {
System.out.println("컵에 따르는 중..");
}
public void addSugarAndMilk() {
System.out.println("설탕과 우유를 추가하는중");
}
}
Tea.java
public class Tea {
//홍차를 우려내는 메소드
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("레몬을 추가하는중");
}
}
문제점
새로운 종류의 음료가 생길때 메서드가 비슷하더라도 계속해서 코드를 작성해야한다. 이미 Coffee랑 Tea에는 중복되는
메서드가 발생하고있다. 이것을 해결하기 위해 템플릿 메서드 패턴을 적용해볼려고 한다.
패턴 적용 이후
이미지화
코드
CaffeinBeverage.java
public abstract class CaffeineBeverage {
//템플릿 메서드 prepareRecipe()
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("물 끓이는 중..");
}
void pourInCup() {
System.out.println("컵에 따르는중..");
}
}
Coffee.java
public class Coffee extends CaffeineBeverage{
public void brew() {
System.out.println("필터로 커피를 우려내는 중..");
}
public void addCondiments() {
System.out.println("설탕과 우유를 추가하는 중..");
}
}
Tea.java
public class Tea extends CaffeineBeverage{
public void brew() {
System.out.println("찻 잎을 우려내는 중..");
}
public void addCondiments() {
System.out.println("레몬을 추가하는중");
}
}
공통되는 부분은 추상클래스인 CaffeineBeverage에서 구현까지 했고 공통되지않는 부분은 상속받는 각 클래스가
직접 구현하도록 진행했다.
'디자인 패턴' 카테고리의 다른 글
[디자인패턴] 추상 팩토리 패턴 (0) | 2023.12.03 |
---|---|
[디자인 패턴] 팩토리 메서드 패턴 (0) | 2023.12.03 |
[디자인패턴] 데커레이터 패턴 (0) | 2023.12.01 |
[디자인패턴] 옵저버 패턴 (0) | 2023.10.31 |
[디자인패턴] 커맨드 패턴 (0) | 2023.10.29 |