템플릿 메서드 패턴
템플릿 메서드 패턴(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