[Design Pattern] Template Method Pattern

younghyun·2022년 10월 26일
0

Design Pattern

목록 보기
13/14
post-thumbnail

Template Method Pattern 이란

알고리즘의 골격을 정의하는 패턴으로, 알고리즘 구조를 변경하지 않고 알고리즘의 일부 내용을 서브 클래스에서 재정의할 수 있는 것이 장점이다.

설계

image
  • AbstractClass

    • 선언된 메소드들이 템플릿 메소드에서 활용됨
  • ConcreteClass

    • 각 클래스에서는 템플릿 메소드에서 요구하는 모든 단계들을 제공해야 함
    • 여러 개의 클래스가 존재할 수 있음

기본구조 1

abstract class AbstractClass {

    // 서브클래스에서 알고리즘을 바꾸지 못하게 하기 위해
    // final로 선언하여 템플릿 메소드 고정
    final void templateMethod() {  
        primitiveOperation1();   // 서브 클래스에서 구현할 추상 메서드 (위임할 수 있는 부분)
        primitiveOperation2();
        concreteOperation();    // 서브 클래스에서 오버라이딩 X
    }
    
    abstract void primitiveOperation1();   
    abstract void primitiveOperation2();
    void concreteOperation() {
        // concreteOperation() 메소드 코드
    }
}

기본구조 2

abstract class AbstractClass {

    final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        hook();   // 구현이 안된 빈 body 
    }
    
    abstract void primitiveOperation1();
    abstract void primitiveOperation2();
    final void concreteOperation();
        // concreteOperation() 메소드 코드
    }
    void hook() {}    // 서브 클래스에 위임해서 알고리즘의 내용을 바꿀 수 있도록 함
}
  • hook()
    • 추상 클래스에 들어 있으며, 아무 일도 하지 않거나 기본 행동을 정의하는 메서드
    • 하위 클래스에서 사용하고 싶을 때만 자유롭게 오버라이딩할 수 있도록 하기 위해서 빈 코드로 제공
      • 추상 메서드(abstract)로 만들었다면, 하위 클래스에서 강제적으로 구현해야 하기 때문

예시

스타버즈 커피 바리스타 매뉴얼

  • 커피 만드는 법
    • 물을 끓인다
    • 끓는 물에 커피를 우려낸다
    • 커피를 컵에 따른다
    • 설탕과 우유를 추가한다
  • 홍차 만드는 법
    • 물을 끓인다
    • 끓는 물에 홍차를 우려낸다
    • 홍차를 컵에 따른다
    • 레몬을 추가한다

Bad Case

image
class Coffee {
    void prepareRecipe() {
        boilWater();    // 물 끓이는 중
        brewCoffeeGrinds();   // 필터를 통해서 커피를 우려내는 중
        pourInCup();    // 컵에 따르는 중
        addSugarAndMilk();   // 설탕과 우유를 추가하는 중
    }
    ...
}
class Tea {
    void prepareRecipe() {
        boilWater();    // 물 끓이는 중
        steepTeaBag();  // 차를 우려내는 중
        pourInCup();    // 컵에 따르는 중
        addLemon();     // 레몬을 추가하는 중
    }        
    ...
}
  • Coffee와 Tea에 중복된 코드가 있음
  • 알고리즘이 바뀌면 서브 클래스를 열어서 여러 군데를 고쳐야 함

Good Case

1. 템플릿 메소드 패턴을 활용

서브 클래스에 있는 알고리즘을 한 군데로 모음
➜ 알고리즘 구현한 클래스 CaffeinBeverage

void prepareRecipe() {
    boilWater();   // 물 끓이는 중
    brew();        // 커피 또는 홍차를 우려내는 중 (brewCoffeeGrinds(), steepTeaBag() 합침)
    pourInCup();   // 컵에 따르는 중
    addCondiments();   // 음료에 맞는 첨가물을 추가하는 중 (addSugarAndMilk(), addLemon() 합침)
}

2. 클래스 구성

image

⭐디자인 원칙: 먼저 연락하지 마세요. 저희가 연락 드리겠습니다.(헐리우드 원칙)

3. 실제 구현

CaffeinBeverage

public abstract class CaffeinBeverage {
    
    // 템플릿 메소드 (알고리즘 고정)
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }
    
    public void boilWater() {
        System.out.println("물 끓이는 중");
    }

    public void pourInCup() {
        System.out.println("컵에 따르는 중");
    }

    abstract void brew();     // 끓는 물에 무언가를 우려낸다 
    
    abstract void addCondiments();    // 무언가를 추가한다
}

Coffee

public class Coffee extends CaffeinBeverage {

    @Override
    public void brew() {
        System.out.println("필터를 통해서 커피를 우려내는 중");
    }

    @Override
    public void addCondiments() {
        System.out.println("설탕과 우유를 추가하는 중");
    }
}

Tea

public class Tea extends CaffeinBeverage {

    @Override
    public void brew() {
        System.out.println("차를 우려내는 중");
    }

    @Override
    public void addCondiments() {
        System.out.println("레몬을 추가하는 중");
    }
}

Main

public class BeverageTestDrive {
    public static void main(String[] args) {
        CoffeeWithHook coffeeHook = new CoffeeWithHook();
        System.out.println("\n커피 준비중…");
        coffeeHook.prepareRecipe();
    }
}
profile
🌱 주니어 백엔드 개발자입니당

0개의 댓글