템플릿 메소드 패턴

taeheon95·2022년 9월 8일
0

디자인 패턴

목록 보기
5/5

부모 객체에는 알고리즘의 뼈대만을 정의하고 각 단계에서 수행할 구체적 처리는 서브클래스 쪽으로 미루는 패턴. 알고리즘의 구조 자체는 그대로 놔둔 채 알고리즘 각 단계의 처리를 서브클래스에서 재정의 할 수 있도록 하는 패턴.

예시

실생활

커피와 홍차를 만든다고 생각하자. 커피와 홍차는 거의 비슷한 과정을 거쳐서 만들어지게 된다.

커피를 만드는 법

  1. 물을 끓인다.
  2. 끓는 물에 커피를 우려낸다.
  3. 커피를 컵에 따른다.
  4. 설탕과 우유를 추가한다.

홍차를 만드는 법

  1. 물을 끓인다.
  2. 끓는 물에 찻잎을 우려낸다.
  3. 홍차를 컵에 따른다.
  4. 레몬을 추가한다.

클래스

우리는 이 과정들을 클래스로 만들어서 나타낼 수 나타낼 수 있다.

커피 만드는 클래스

public class Coffee {
    void prepareRecipe() {
        boilWater();
        brewCoffeeGrinds();
        pourInCup();
        addSugarAndMilk();
    }
    public void boilWater() {
    }
    
    public void brewCoffeeGrinds() {
    }
    
    public void pourInCup() {
    }
    
    public void addSugarAndMilk() {
    }
}

홍차를 우려내는 클래스

public class Tea {
    void prepareRecipe() {
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }

    public void boilWater() {
    }

    public void steepTeaBag() {

    }

    public void pourInCup() {

    }

    public void addLemon() {

    }

}

이 두가지 클래스는 중복된 점이 많다. 만약 실제 클래스가 이렇게 제작되게 된다면 클래스의 변경이 일어나게 될 시 비슷한 두 클래스의 동작을 변경하기 위해서 두 클래스를 변경해야 하고 클래스를 각각 변경해야 한다.

그런데 이 두 클래스가 하는 일인 커피, 홍차의 제조를 생각하면 두 제조법의 알고리즘이 같다는 것을 알 수 있다.

제조법

  1. 물을 끓인다.
  2. 뜨거운 물을 사용해서 커피 또는 찻잎을 우려낸다.
  3. 만들어진 음료를 컵에 따른다.
  4. 각 음료에 맞는 첨가물을 추가한다.

우리는 이에 따라 만들어진 클래스들도 추상화 작업을 통해서 클래스의 중복된 코드와 알고리즘을 줄이고 공통화 시킬수 있다.

템플릿 메소드 적용

일단 우리는 레시피를 적용하는 함수를 보자

void prepareRecipe() {
    boilWater();
    brewCoffeeGrinds();
    pourInCup();
    addSugarAndMilk();
}
void prepareRecipe() {
    boilWater();
    steepTeaBag();
    pourInCup();
    addLemon();
}

우리는 첫번째로 brewCoffeeGrinds(커피를 필터로 우려내는 일)와 steepTeaBag(티백을 물에 넣어서 홍차를 우려내는 일)이 거의 같다는 것을 안다. 그럼 우리는 두 함수를 brew 라는 함수로 공통화 시킬 수 있다.

또한 설탕과 우유를 추가하는 일과 레몬을 추가하는 일도 그와 같다는 것을 알 수 있다. 이 두가지 행위를 addCondiments 라는 함수로 공통화 시킬 수 있다.

void prepareRecipe() {
    boilWater();
    brew();
    pourInCup();
    addCondiments();
}

이 함수를 사용하는 슈퍼 클래스를 만들어서 적용해보자

public abstract class Beverage {
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    abstract void brew();

    abstract void addCondiments();

    void boilWater() {
        System.out.println("물 끓이는 중");
    }

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

그리고 커피와 홍차 음료 만드는 방법 두 클래스를 보자

Coffee 클래스

public class Coffee extends Beverage {
    public void brew() {
        System.out.println("필터로 커피를 우려내는 중");
    }

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

홍차 클래스

public class Tea extends Beverage {
    public void brew() {
        System.out.println("찻잎을 우려내는 중");
    }

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

이렇게 클래스의 알고리즘적으로 공통된 과정을 부모 클래스에서 정의하고 자식 클래스에서 세부적인 알고리즘 처리를 함으로 인해서 각 클래스마다 독립성에 대한 보장과 중복된 코드를 줄일 수 있다.

템플릿 메소드 패턴의 장단점

장점

  1. 중복 코드를 줄일 수 잇다.
  2. 자식 클래스의 역할을 줄여 핵심 로직의 관리가 용이하다.
  3. 좀 더 객체지향적으로 구성할 수 있다.

단점

  1. 추상 메소드가 많아지면서 클래스 관리가 복잡해진다.
  2. 클래스 간의 관계와 코드가 꼬여버릴 염려가 있다.

템플릿 메소드를 사용하는 예시

스프링의 dispatcher servlet

스프링의 DispatcherServlet은 하위 알고리즘 구현을 controller 에게 맡기고 자신은 공통적인 처리인 view 처리와 url 맵핑을 처리해서 스프링 프레임워크 사용자에게 편리성을 제공하는 방식으로 사용 되고 있다.

profile
계속 공부하는 개발자

0개의 댓글