본문 바로가기
Design Pattern/행동 패턴(Behavioral Patterns)

템플릿 메서드(Template Method) - 행동 패턴(Behavioral Patterns)

by 김 민 준 2024. 5. 25.

 

템플릿 메서드 패턴은 알고리즘의 구조를 정의하고, 알고리즘의 일부 단계를 서브 클래스에서 구현할 수 있도록 한다. 알고리즘의 뼈대는 상위 클래스에서 제공하고 세부 구현은 하위 클래스에서 제공한다.

 

주요 개념 부터 알아보자.

 

1. Abstract Class (추상 클래스) : 알고리즘의 뼈대를 정의하는 템플릿 메서드를 포함한다. 알고리즘의 각 단계를 정의하며, 일부 단계는 추상 메서드로 선언하여 서브 클래스에서 구현하도록 한다.

2. Concrete Class (구체 클래스) : 추상 클래스에서 정의된 추상 메서드를 구현하여 알고리즘의 각 단계를 정의한다. 

 

예시 소스코드를 살펴보자.

 

요리를 하는 과정을 템플릿 메서드 패턴으로 구현해본다. 요리는 재료준비, 요리, 설거지 이런 단계가 가장 큰 틀이다 각 세부 구현은 요리 종류에 따라 달라질 수 있다.

 

abstract class Cooking {
    // 템플릿 메서드
    public final void cook() {
        prepareIngredients();
        cookDish();
        cleanUp();
    }

    // 알고리즘의 단계들
    protected abstract void prepareIngredients();
    protected abstract void cookDish();

    // 공통 단계
    protected void cleanUp() {
        System.out.println("Cleaning up the kitchen...");
    }
}

 

class ItalianCooking extends Cooking {
    @Override
    protected void prepareIngredients() {
        System.out.println("Preparing ingredients for Italian dish...");
    }

    @Override
    protected void cookDish() {
        System.out.println("Cooking Italian dish...");
    }
}

class JapaneseCooking extends Cooking {
    @Override
    protected void prepareIngredients() {
        System.out.println("Preparing ingredients for Japanese dish...");
    }

    @Override
    protected void cookDish() {
        System.out.println("Cooking Japanese dish...");
    }
}

 

public class TemplateMethodPatternDemo {
    public static void main(String[] args) {
        Cooking italianCooking = new ItalianCooking();
        italianCooking.cook();

        System.out.println();

        Cooking japaneseCooking = new JapaneseCooking();
        japaneseCooking.cook();
    }
}

 

// 출력


//Preparing ingredients for Italian dish...
//Cooking Italian dish...
//Cleaning up the kitchen...

//Preparing ingredients for Japanese dish...
//Cooking Japanese dish...
//Cleaning up the kitchen...

 

설거지는 모두 동일하겠지만 이탈리안 요리를 준비하거나 일식을 준비하는 과정은 다르고 결과도 다를것이다.

 

서브클래스의 책임이 증가하지만 코드를 재사용할 수 있고 서브 클래스에서 구현하는 단계들을 통해 유연성을 가질 수 있다. 

 

현업에서도 많이 사용하는 웹 애플리케이션 요청 처리에 대해서 소스코드로 살펴보며 패턴을 이해하보자.

 

요청을 처리하고 결과를 반환하기전에 인증, 권한 확인, 로깅 등의 작업을 수행해야 한다고 생각해보자.

 

abstract class HttpRequestHandler {
    // 템플릿 메서드
    public final void handleRequest() {
        authenticate();
        authorize();
        handle();
        logRequest();
    }

    protected abstract void authenticate();
    protected abstract void authorize();
    protected abstract void handle();

    // 공통 단계
    protected void logRequest() {
        System.out.println("Logging request...");
    }
}

 

 

class GetRequestHandler extends HttpRequestHandler {
    @Override
    protected void authenticate() {
        System.out.println("Authenticating GET request...");
    }

    @Override
    protected void authorize() {
        System.out.println("Authorizing GET request...");
    }

    @Override
    protected void handle() {
        System.out.println("Handling GET request...");
    }
}

 

class PostRequestHandler extends HttpRequestHandler {
    @Override
    protected void authenticate() {
        System.out.println("Authenticating POST request...");
    }

    @Override
    protected void authorize() {
        System.out.println("Authorizing POST request...");
    }

    @Override
    protected void handle() {
        System.out.println("Handling POST request...");
    }
}

 

public class TemplateMethodPatternHttpRequestDemo {
    public static void main(String[] args) {
        HttpRequestHandler getRequestHandler = new GetRequestHandler();
        getRequestHandler.handleRequest();

        System.out.println();

        HttpRequestHandler postRequestHandler = new PostRequestHandler();
        postRequestHandler.handleRequest();
    }
}
// 출력 

//Authenticating GET request...
//Authorizing GET request...
//Handling GET request...
//Logging request...

//Authenticating POST request...
//Authorizing POST request...
//Handling POST request...
//Logging request...

 

이런식으로 구현하면 공통된 처리 흐름을 유지하면서 각 단계의 구체적인 구현을 다양하게 할 수 있다.