템플릿 메서드 template method 패턴 - 타입스크립트 예시
요약
디자인 패턴 중 템플릿 메서드 template method 패턴을 타입스크립트 코드와 함께 알아봅니다.
템플릿 메서드 (Template Method) 패턴 요약
패턴 종류 | 핵심 키워드 |
---|---|
템플릿 메서드 (Template Method) | 변하지 않는 부분은 상위 클래스, 변하는 부분은 하위 클래스에서 재정의(override) |

템플릿 메서드 (Template Method) 패턴
템플릿 메서드 패턴은 알고리즘의 골격(뼈대)은 상위 클래스에서 정의하고, 알고리즘의 특정 단계들은 하위 클래스에서 재정의(override)할 수 있도록 하는 패턴입니다. 즉, 전체적인 로직의 흐름(템플릿)은 부모가 통제하되, 세부적인 내용은 자식에게 위임하는 방식입니다.
앞서 비유로 들었던 '라면 끓이기' 가 바로 이 패턴의 완벽한 예시입니다. 라면을 끓이는 과정은 대체로 정해져 있습니다.
- 물을 끓인다.
- 면과 스프를 넣는다.
- (선택) 계란, 치즈, 만두 등 추가 재료를 넣는다.
- 그릇에 담아낸다.
이 전체 과정이 템플릿 메서드입니다. 여기서 '물을 끓인다'나 '면과 스프를 넣는다' 같은 단계는 모든 라면에서 동일하지만, '추가 재료를 넣는다'는 단계는 어떤 라면을 끓이느냐에 따라 달라집니다. 템플릿 메서드 패턴은 이처럼 변하지 않는 부분은 상위 클래스에 두고, 변하는 부분만 하위 클래스에서 구현하도록 하여 코드의 중복을 줄이고 일관된 구조를 유지하게 해줍니다.
기본 구조
- AbstractClass: 템플릿 메서드를 정의하는 추상 클래스입니다. 템플릿 메서드는 알고리즘의 각 단계를 나타내는 여러 메서드를 순서대로 호출합니다. 이 중 일부는 하위 클래스에서 구현해야 하는 추상 메서드(
abstract method
)이거나, 선택적으로 재정의할 수 있는hook
메서드일 수 있습니다. - ConcreteClass:
AbstractClass
를 상속받아, 알고리즘의 특정 단계를 실제로 구현하는 하위 클래스입니다.
예시: 세상의 모든 라면 만들기
다양한 종류의 라면을 만드는 과정을 템플릿 메서드 패턴으로 구현해 보겠습니다.
먼저, 라면 제조의 전체적인 흐름을 정의하는 AbstractClass
인 RamenRecipe
를 만듭니다.
// AbstractClass: 알고리즘의 뼈대를 정의
abstract class RamenRecipe {
// 템플릿 메서드: 전체적인 흐름을 제어하며, 재정의를 막는 것이 좋음
cook(): void {
this.boilWater();
this.addNoodlesAndSoup();
this.addExtraIngredients(); // 이 단계가 자식 클래스마다 달라짐
this.serve();
}
// 하위 클래스에서 반드시 구현(오버라이드)해야 하는 추상(abstract) 메서드
// protected 접근 제어자는 하위 클래스에서만 접근 가능하도록 합니다.`
protected abstract addExtraIngredients(): void;
// 모든 클래스에서 동일하게 사용되는 구체적인 메서드
private boilWater(): void {
console.log("냄비에 물을 끓입니다.");
}
private addNoodlesAndSoup(): void {
console.log("면과 분말 스프, 후레이크를 넣습니다.");
}
private serve(): void {
console.log("맛있게 보이도록 그릇에 옮겨 담습니다.");
}
}
이제 RamenRecipe
를 상속받아 구체적인 라면 레시피를 만드는 ConcreteClass
인 CheeseRamen
과 DumplingRamen
을 구현합니다.
// ConcreteClass: 치즈 라면
class CheeseRamen extends RamenRecipe {
protected addExtraIngredients(): void {
console.log("체다 치즈 한 장을 사르르 녹여줍니다.");
}
}
// ConcreteClass: 만두 라면
class DumplingRamen extends RamenRecipe {
protected addExtraIngredients(): void {
console.log("냉동실에 있던 왕만두 세 개를 투하합니다.");
}
}
// 클라이언트 코드
console.log("--- 치즈 라면 만들기 ---");
const cheeseRamen = new CheeseRamen();
cheeseRamen.cook();
// 출력:
// 냄비에 물을 끓입니다.
// 면과 분말 스프, 후레이크를 넣습니다.
// 체다 치즈 한 장을 사르르 녹여줍니다.
// 맛있게 보이도록 그릇에 옮겨 담습니다.
console.log("
--- 만두 라면 만들기 ---");
const dumplingRamen = new DumplingRamen();
dumplingRamen.cook();
// 출력:
// 냄비에 물을 끓입니다.
// 면과 분말 스프, 후레이크를 넣습니다.
// 냉동실에 있던 왕만두 세 개를 투하합니다.
// 맛있게 보이도록 그릇에 옮겨 담습니다.
cook()
이라는 템플릿 메서드 덕분에 어떤 라면이든 일관된 순서로 만들어집니다. 개발자는 addExtraIngredients()
처럼 달라지는 부분에만 집중하면 됩니다. 만약 '계란 라면'을 추가하고 싶다면, addExtraIngredients()
에서 계란을 추가하는 EggRamen
클래스를 새로 만들기만 하면 됩니다.
템플릿 메서드 패턴 중요 키워드
- 알고리즘의 골격을 상위 클래스에서 정의합니다.
- 상속을 통해 동작을 확장합니다. (전략 패턴은 위임을 사용)
- 코드 중복을 제거하고 일관된 구조를 강제할 수 있습니다.
- 상위 작업의 구조를 바꾸지 않으면서 서브 클래스로 작업 일부분을 수행할 수 있습니다.
문제 | 어떤 작업을 처리하는 일부분을 서브 클래스로 캡슐화하여 전체 일을 수행하는 구조는 바꾸지 않으면서 특정 단계에서 수행하는 내역을 바꾸는 패턴으로 일반적으로 상위 클래스(추상 클래스)에는 추상 메서드를 통해 기능의 골격을 제공하고, 하위 클래스(구체 클래스)의 메서드에는 세부 처리를 구체화하는 방식으로 사용하는 디자인 패턴은? |
보기 | |
답변 | |
정답 | 정답 보기 |