템플릿 메서드 패턴
템플릿 메서드 패턴(Template Method Pattern)은 알고리즘의 전체 흐름을 상위 클래스에서 정의하고, 알고리즘의 세부 구현을 서브클래스에 위임하는 방식이다. 여기서 말하는 알고리즘은 넓은 의미에서 비즈니스 로직이라고 볼 수 있다. 이 패턴은 비즈니스 로직의 흐름을 관리하면서도, 각 단계를 서브클래스에서 구체적으로 정의할 수 있게 해줍니다. 이를 통해 코드의 재사용성과 유연성을 높이며, 특히 프레임워크 개발에서 자주 활용됩니다. 템플릿 메서드 패턴을 사용하면 프레임워크의 핵심 흐름은 그대로 유지하면서도, 사용자는 필요에 맞게 세부적인 로직만 수정할 수 있어 효율적인 확장이 가능하다.
템플릿 메서드 패턴은 상위 클래스가 제공하는 기본 알고리즘 흐름 내에서 서브클래스가 특정 행위를 선택적으로 추가할 수 있도록 훅 메서드(Hook Method)를 제공하기도 한다. 이 훅 메서드는 일반적으로 상위 클래스에서 기본적으로 빈 형태로 제공되며, 서브클래스는 이를 선택적으로 오버라이드하여 추가적인 동작이나 기능을 구현할 수 있다. 훅 메서드는 알고리즘의 흐름을 변경하지 않으면서도 서브클래스가 필요에 따라 세부 구현을 확장할 수 있는 지점을 제공하며, 이를 통해 코드의 유연성을 높이고, 재사용 가능성을 확보할 수 있다.
[ 파사드 패턴 ] 포스트에서 작성했던 예시 코드 PizzaStore 클래스를 보면 외부에 제공되는 공용 인터페이스는 항상 동일한 로직을 따라야 함을 알 수 있다. 여기에 템플릿 메서드 패턴을 추가하면 아래와 같이 변경될 것이다. 피자를 만들어봤는데 망하면 피자를 버리는 로직을 훅 메서드로 제공하여 피자 퀄리티 확인을 선택적으로 할 수 있도록 했다.
// 파사드 클래스 (상위 클래스)
abstract class PizzaStore {
// 공통 알고리즘 흐름 (템플릿 메서드)
public processOrder(): void {
this.preparePizza();
// 피자를 버려야 할 조건을 확인
if (this.shouldDiscardPizza()) {
return;
}
this.packPizza();
this.servePizza();
}
// 각 단계는 서브클래스에서 구현하도록 강제하는 추상 메서드
protected abstract preparePizza(): void;
protected abstract packPizza(): void;
protected abstract servePizza(): void;
// 피자를 포기해야 하는 조건을 체크하는 훅 메서드
protected shouldDiscardPizza(): boolean {
return false; // 기본적으로 피자는 버리지 않음
}
}
// 클라이언트 코드 (서브클래스)
class StandardPizzaStore extends PizzaStore {
private pizza: Pizza;
private box: Box;
private plasticWrap: PlasticWrap;
constructor() {
super();
this.pizza = new Pizza();
this.box = new Box();
this.plasticWrap = new PlasticWrap();
}
// 피자 준비 (구체적인 구현)
protected preparePizza(): void {
console.log('피자 준비 시작...');
this.pizza.dough();
this.pizza.topping();
this.pizza.bake();
this.pizza.cut();
}
// 피자 포장 (구체적인 구현)
protected packPizza(): void {
console.log('피자 포장 시작...');
this.box.fold();
this.box.putPizza();
this.plasticWrap.wrap();
}
// 피자 제공 (구체적인 구현)
protected servePizza(): void {
console.log('피자 제공!');
}
// 피자를 버려야 할 조건 (예: 품질 불량, 주문 취소 등)
// 서브클래스에서 오버라이드하여 실제 조건을 처리
protected shouldDiscardPizza(): boolean {
// 예시로, 임의로 피자를 버릴 조건을 설정 (예: 품질 불량)
const isBadQuality = Math.random() > 0.8; // 20% 확률로 불량 피자
if (isBadQuality) {
console.log('피자 품질 불량, 버립니다.');
}
return isBadQuality;
}
}
// 클라이언트 코드
const pizzaStore = new StandardPizzaStore();
pizzaStore.processOrder();
블로그의 정보
Ayden's journal
Beard Weard Ayden