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

서버란·2024년 10월 13일

CS 지식

목록 보기
20/25

템플릿 메서드 패턴(Template Method Pattern)은 객체지향 프로그래밍에서 상위 클래스에서 알고리즘의 구조를 정의하고, 세부적인 단계는 하위 클래스에서 구현하도록 하는 디자인 패턴입니다.
이 패턴은 알고리즘의 공통된 구조는 재사용하면서, 세부 구현을 필요에 맞게 변경할 수 있도록 유연성을 제공합니다.

1. 템플릿 메서드 패턴의 정의

템플릿 메서드 패턴은 상위 클래스에 알고리즘의 뼈대를 정의하고, 구체적인 단계는 하위 클래스에서 구현하는 구조를 따릅니다. 즉, 상위 클래스에서 템플릿 메서드라는 메서드가 전체 알고리즘의 순서를 정의하고, 그 알고리즘을 구성하는 여러 메서드 중 일부는 하위 클래스에서 구체적인 내용이 구현됩니다.

이 패턴을 사용하면 알고리즘의 기본 흐름은 변경하지 않고도, 특정 단계의 동작만을 변경하는 것이 가능합니다. 이는 코드의 재사용성을 높이고, 유지보수를 용이하게 해줍니다.

2. 구성 요소

템플릿 메서드 패턴은 다음과 같은 구성 요소를 가지고 있습니다.

  1. 추상 클래스(Abstract Class):
  • 알고리즘의 공통된 구조를 정의합니다.
  • 템플릿 메서드(Template Method)는 final로 선언되어 하위 클래스에서 재정의할 수 없습니다. 이 메서드는 고정된 알고리즘의 순서를 나타냅니다.
  • 세부 동작을 정의하는 몇 가지 추상 메서드(Abstract Method)구현된 메서드(Concrete Method)가 포함됩니다.
  1. 템플릿 메서드(Template Method):
  • 알고리즘의 전체 구조를 정의하는 메서드입니다. 알고리즘의 각 단계를 호출하는 메서드로 이루어져 있으며, 이 메서드는 final로 선언되어 하위 클래스에서 오버라이딩할 수 없습니다.
  • 각 단계는 개별 메서드로 나뉘어 있으며, 일부는 상위 클래스에서 기본 구현을 제공하고, 일부는 하위 클래스에서 재정의(오버라이딩)할 수 있습니다.
  1. 추상 메서드(Abstract Methods):
  • 템플릿 메서드에서 호출되는 메서드 중 구체적인 동작이 정의되지 않은 메서드로, 하위 클래스에서 반드시 구현해야 합니다.
  1. 하위 클래스(Concrete Class):
  • 상위 클래스에서 정의된 템플릿 메서드의 각 단계를 구체적으로 구현합니다.
  • 필요에 따라 추상 메서드를 구현하거나, 상위 클래스의 기본 구현을 그대로 사용할 수도 있습니다.

3. 동작 방식

템플릿 메서드 패턴의 핵심은 상위 클래스에서 정의한 템플릿 메서드가 특정 알고리즘의 전체적인 흐름을 담당한다는 것입니다. 템플릿 메서드는 순서를 고정하고, 그 내부에서 호출되는 메서드 중 일부는 하위 클래스에서 오버라이딩을 통해 구체적으로 변경할 수 있습니다.

  • 상위 클래스에서 알고리즘의 큰 흐름을 고정합니다.
  • 하위 클래스에서는 구체적인 동작만을 오버라이딩하여 변경합니다.

예를 들어, 어떤 작업을 수행하는 과정이 다음과 같이 고정된 4단계로 이루어졌다고 가정해봅시다:

  1. 작업 준비(prepare)
  2. 작업 실행(execute)
  3. 작업 후처리(postProcess)
  4. 작업 완료 알림(notify)

여기서 prepare과 notify는 상위 클래스에서 공통으로 구현할 수 있고, execute와 postProcess는 하위 클래스마다 다르게 구현될 수 있습니다. 상위 클래스는 알고리즘의 순서(템플릿 메서드)를 고정하고, 하위 클래스에서 세부적인 단계만 변경하는 식입니다.

4. 템플릿 메서드 패턴의 예시 (자바)

다음은 템플릿 메서드 패턴의 간단한 Java 코드 예시입니다.

// 추상 클래스: 알고리즘의 기본 흐름을 정의
abstract class Game {
    // 템플릿 메서드: 게임 진행 과정의 큰 틀을 정의
    public final void play() {
        initialize();
        startPlay();
        endPlay();
    }

    // 각 단계는 하위 클래스에서 구체적으로 구현해야 함
    abstract void initialize();
    abstract void startPlay();
    abstract void endPlay();
}

// 하위 클래스 1: 축구 게임
class Football extends Game {
    @Override
    void initialize() {
        System.out.println("축구 게임 준비 완료!");
    }

    @Override
    void startPlay() {
        System.out.println("축구 게임 시작!");
    }

    @Override
    void endPlay() {
        System.out.println("축구 게임 종료!");
    }
}

// 하위 클래스 2: 농구 게임
class Basketball extends Game {
    @Override
    void initialize() {
        System.out.println("농구 게임 준비 완료!");
    }

    @Override
    void startPlay() {
        System.out.println("농구 게임 시작!");
    }

    @Override
    void endPlay() {
        System.out.println("농구 게임 종료!");
    }
}

// 클라이언트 코드
public class Main {
    public static void main(String[] args) {
        Game football = new Football();
        football.play(); // 축구 게임의 진행 과정 출력

        Game basketball = new Basketball();
        basketball.play(); // 농구 게임의 진행 과정 출력
    }
}

설명:

  • 추상 클래스 Game에서 play()라는 템플릿 메서드가 정의됩니다. 이 메서드는 initialize(), startPlay(), endPlay()라는 단계를 차례로 실행합니다.
  • initialize(), startPlay(), endPlay()는 추상 메서드로 정의되어 있고, 각각의 하위 클래스인 Football과 Basketball에서 이 메서드들을 구체적으로 구현합니다.
  • play() 메서드는 전체 게임의 진행 순서를 고정한 채, 구체적인 게임 로직은 각 하위 클래스에서 다르게 구현할 수 있습니다.

5. 템플릿 메서드 패턴의 장점

  • 코드 재사용성: 알고리즘의 공통된 부분을 상위 클래스에서 정의하고, 세부적인 구현만 하위 클래스에서 다르게 구현할 수 있어 코드 중복이 줄어듭니다.
  • 유연성: 알고리즘의 구조를 변경하지 않고, 세부 구현만 바꿀 수 있습니다.
  • 관리 용이성: 알고리즘의 흐름을 변경하지 않고도, 특정 부분의 구현만 수정할 수 있으므로 유지보수가 쉬워집니다.

6. 템플릿 메서드 패턴의 단점

  • 하위 클래스의 증가: 알고리즘의 세부 구현이 다양해질수록 하위 클래스를 많이 작성해야 하므로 클래스가 많아질 수 있습니다.
  • 추상화된 메서드의 제약: 상위 클래스에서 정의한 메서드의 형태(파라미터, 반환값 등)를 하위 클래스가 따라야 하므로, 하위 클래스에 어느 정도 제약이 따를 수 있습니다.

7. 템플릿 메서드 패턴을 사용하는 경우

  • 알고리즘의 구조는 고정하면서, 알고리즘의 일부 단계만 다양하게 변경해야 할 때.
  • 다양한 방식으로 특정 작업을 처리하는 공통된 흐름이 있는 경우.
  • 코드 중복을 방지하고, 알고리즘의 일관성을 유지하고 싶을 때.

Q1: 템플릿 메서드 패턴을 사용하여 게임의 여러 레벨에서 다른 행동을 하게 하려면 어떻게 설계할 수 있을까요?

답: 게임의 각 레벨이 서로 다른 규칙이나 환경에서 작동한다면, 템플릿 메서드 패턴을 활용하여 각 레벨에 대한 공통된 구조는 유지하면서, 레벨별로 특정 동작을 하위 클래스에서 정의할 수 있습니다. 예를 들어, 추상 클래스에서 initialize(), startPlay(), endPlay() 메서드를 정의하고, 각 레벨을 하위 클래스로 분리하여 레벨별로 다르게 구현할 수 있습니다. 레벨 1, 레벨 2, 레벨 3 등을 하위 클래스로 만들어 각 레벨에 맞는 게임 규칙을 구현하면 됩니다.

Q2: 템플릿 메서드 패턴을 사용한 코드를 유지보수할 때, 하위 클래스에서 수정해야 할 부분이 많아질 경우 이를 어떻게 최적화할 수 있을까요?

답: 하위 클래스에서 수정해야 할 부분이 많아지면 코드 관리가 어려울 수 있습니다. 이를 최적화하려면 다음과 같은 방법을 고려할 수 있습니다:

  • 훅 메서드(Hook Method)를 활용: 상위 클래스에서 기본 구현을 제공하고, 하위 클래스에서 필요한 경우만 오버라이딩하도록 유도합니다. 이렇게 하면 하위 클래스에서 불필요한 메서드 구현을 줄일 수 있습니다.
  • 상속 대신 구성(Composition)을 사용: 하위 클래스에서 너무 많은 변경이 필요할 경우 상속 대신 구성을 고려할 수 있습니다. 즉, 하위 클래스가 다른 객체에 작업을 위임하여 필요한 기능만 추가하거나 수정하는 방식을 사용합니다.

Q3: 템플릿 메서드 패턴이 적합하지 않은 상황은 어떤 경우인가요?

답: 템플릿 메서드 패턴이 적합하지 않은 상황은 다음과 같습니다:

  • 알고리즘의 흐름이 자주 변경되거나 유동적일 때: 템플릿 메서드 패턴은 알고리즘의 흐름이 고정되어 있을 때 적합합니다. 알고리즘 자체가 자주 변하는 경우에는 이 패턴이 비효율적일 수 있습니다.
  • 단순한 클래스 구조에서 오버엔지니어링: 너무 간단한 구조에서는 템플릿 메서드 패턴을 사용하면 불필요하게 복잡도가 증가할 수 있습니다. 이런 경우에는 코드 재사용성이나 유연성보다 간결함을 유지하는 것이 더 중요할 수 있습니다.
  • 각 클래스가 완전히 다른 작업을 해야 하는 경우: 상속 구조보다 개별 클래스들이 각자 독립적으로 동작해야 할 때는 템플릿 메서드 패턴을 사용하는 것이 비효율적일 수 있습니다. 상속의 제약으로 인해 하위 클래스의 구현이 제한될 수 있기 때문입니다.
profile
백엔드에서 서버엔지니어가 된 사람

0개의 댓글