템플릿 메서드 패턴(Template Method Pattern)

박세건·2024년 5월 25일
0

디자인 패턴

목록 보기
15/17
post-thumbnail

템플릿 메서드 패턴이란, 여러 클래스에서 공통으로 사용되는 메서드를 템플릿화 하여 상위 클래스로 정의하고, 하위 클래스에서 세부 동작을 설정하는 행위 패턴이다.
즉, 변하지 않는 기능을 상위클래스에 정의(템플릿 메서드)하고 자주 변하는 기능을 하위 클래스에서 구현

✅ 인터페이스는 왜 안 되나요?

🔹 자바 8 이전 인터페이스는

  • 필드를 가질 수 없고,
  • 일반 메소드 구현도 못했음 (무조건 추상 메소드만 가짐)
    → 그래서 템플릿 메소드처럼 "알고리즘의 틀"을 구현할 수 없음.

🔹 자바 8 이후 인터페이스는

  • default 메소드가 생겼지만,
  • 상속 구조 없이 "부분 구현 + 상속 + 재사용"을 섞어 쓰기엔 여전히 한계가 있어.
  • 상태(state)를 가질 수 없는 인터페이스로는 템플릿 메소드 패턴의 의도가 약해짐.

템플릿이란, 변하지 않게 고정시켜놓는 것을 의미한다.
템플릿 메서드란, 상위 클래스에 작동시킬 메서드를 순서대로 정의한다.
이 순서대로 진행되는 로직속에서 변하지않는 메서드와 자주 변하는 메서드가 존재하고, 자주 변하는 메서드를 하위 클래스에서 정의한다.

구조

  • AbstractClass(추상 클래스) : 템플릿 메서드를 소유하고있는 최상위 객체
  • ConcreteClass : 최상위 객체에게 상속받는 하위 객체

hook 메서드

최상위 객체의 템플릿 메서드를 제어하고 싶을때 사용하는 메서드
조건을 사용해서 템플릿 메서드의 흐름을 변경

예시 코드

AbstractTemplate 클래스(최상위 객체)

abstract class Beverage {

    public final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) {  // Hook 메서드 사용
            addCondiments();
        }
    }

    private void boilWater() {
        System.out.println("물을 끓입니다.");
    }

    private void pourInCup() {
        System.out.println("컵에 따릅니다.");
    }

    abstract void brew();
    abstract void addCondiments();

    // Hook 메서드: 기본적으로 첨가물을 추가하지 않음
    boolean customerWantsCondiments() {
        return true;
    }
}

구현체 코드

class Coffee extends Beverage {
    @Override
    void brew() {
        System.out.println("커피를 우려냅니다.");
    }

    @Override
    void addCondiments() {
        System.out.println("설탕과 우유를 추가합니다.");
    }

    @Override
    boolean customerWantsCondiments() {
        return true;  // 커피는 기본적으로 첨가물을 추가
    }
}

class Tea extends Beverage {
    @Override
    void brew() {
        System.out.println("차를 우려냅니다.");
    }

    @Override
    void addCondiments() {
        System.out.println("레몬을 추가합니다.");
    }

    @Override
    boolean customerWantsCondiments() {
        return false;  // 차는 기본적으로 첨가물을 추가하지 않음
    }
}
public class Main {
    public static void main(String[] args) {
        Beverage coffee = new Coffee();
        coffee.prepareRecipe();  // 커피는 첨가물을 추가

        Beverage tea = new Tea();
        tea.prepareRecipe();  // 차는 첨가물을 추가하지 않음
    }
}

사용 시기

  • 동일한 기능을 상위 클래스 에서 정의하면 확장하고, 변화가 필요한 부분은 하위 클래스에서 구현할때
  • 클라이언트는 특정 단계(구체화한 메서드)만 확장하고, 전체적인 알고리즘의 구조는 확장하지 않도록 할때

장점

  • 대규모 알고리즘의 특정 부분만 재정의 하도록 하여, 알고리즘의 큰 형태는 영향을 받지 않음
  • 추상클래스로 코드의 중복을 줄임
  • 핵심 로직을 상위클래스에서 관리하기 때문에 관리가 용이

단점

  • 정해진 골격이 있어서 유연성이 제한될 수 있음
  • 알고리즘이 복잡하면 템플릿 로직 구현이 어려움
  • 추상 메서드가 많아지면 관리가 복잡
  • 상위클래스를 수정하면 하위클래스도 따라서 모두 수정
profile
멋있는 사람 - 일단 하자

0개의 댓글