본문 바로가기
CS(Computer Science)지식/[C++] 디자인 패턴

템플릿 메서드 패턴(Template Method Pattern)이해하기 : 쉽게 설명한 디자인 패턴(C++)

by 엔지니어 청년 2024. 1. 29.

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


템플릿 메서드 패턴은 알고리즘의 구조를 메서드에 정의하고, 일부 단계를 서브클래스에서 오버라이드하는 디자인 패턴입니다. 이 패턴을 사용하면 알고리즘의 구조를 변경하지 않고 알고리즘의 특정 단계를 재정의할 수 있습니다.

템플릿 메서드 패턴은 다음 두 가지 주요 구성 요소로 이루어져 있습니다:

  1. AbstractClass: 템플릿 메서드를 정의하고, 알고리즘의 각 단계를 정의하는 메서드(일부는 기본 구현을 제공하고, 일부는 서브클래스에서 구현해야 함)를 포함합니다.
  2. ConcreteClass: AbstractClass에서 정의한 메서드를 오버라이드하여 알고리즘의 특정 단계를 구현합니다.

예시 코드


다음은 C++로 작성된 간단한 템플릿 메서드 패턴의 예입니다:

#include <iostream>

// AbstractClass
class AbstractClass {
public:
    void templateMethod() {
        baseOperation1();
        requiredOperations1();
        baseOperation2();
        hook1();
        requiredOperation2();
        baseOperation3();
        hook2();
    }

protected:
    void baseOperation1() {
        std::cout << "AbstractClass says: I am doing the bulk of the work\n";
    }
    void baseOperation2() {
        std::cout << "AbstractClass says: But I let subclasses override some operations\n";
    }
    void baseOperation3() {
        std::cout << "AbstractClass says: But I am doing the bulk of the work anyway\n";
    }
    virtual void requiredOperations1() = 0;
    virtual void requiredOperation2() = 0;

    virtual void hook1() {}
    virtual void hook2() {}
};

// ConcreteClass
class ConcreteClass1 : public AbstractClass {
protected:
    void requiredOperations1() override {
        std::cout << "ConcreteClass1 says: Implemented Operation1\n";
    }
    void requiredOperation2() override {
        std::cout << "ConcreteClass1 says: Implemented Operation2\n";
    }
};

class ConcreteClass2 : public AbstractClass {
protected:
    void requiredOperations1() override {
        std::cout << "ConcreteClass2 says: Implemented Operation1\n";
    }
    void requiredOperation2() override {
        std::cout << "ConcreteClass2 says: Implemented Operation2\n";
    }
    void hook1() override {
        std::cout << "ConcreteClass2 says: Overridden Hook1\n";
    }
};

void clientCode(AbstractClass* class_) {
    class_->templateMethod();
}

int main() {
    std::cout << "Same client code can work with different subclasses:\n";
    ConcreteClass1* concreteClass1 = new ConcreteClass1;
    clientCode(concreteClass1);
    std::cout << "\n";
    std::cout << "Same client code can work with different subclasses:\n";
    ConcreteClass2* concreteClass2 = new ConcreteClass2;
    clientCode(concreteClass2);
    delete concreteClass1;
    delete concreteClass2;
    return 0;
}

위 코드에서 AbstractClass는 템플릿 메서드인 templateMethod()를 정의하고 있습니다. 이 메서드는 알고리즘의 각 단계를 정의하는 메서드를 호출합니다. ConcreteClass1ConcreteClass2AbstractClass에서 정의한 메서드를 오버라이드하여 알고리즘의 특정 단계를 구현합니다.

클래스 다이어그램


    +-----------------+
    |  AbstractClass  |
    +-----------------+
    | templateMethod()|
    +-----------------+
            ^
            |
    +-----------------+     +-----------------+
    | ConcreteClass1  |     | ConcreteClass2  |
    +-----------------+     +-----------------+
    | requiredOperations1() |     | requiredOperations1() |
    | requiredOperation2()  |     | requiredOperation2()  |
    | hook1()               |     | hook1()               |
    +-----------------+     +-----------------+

이 패턴을 사용하면 알고리즘의 구조를 변경하지 않고 알고리즘의 특정 단계를 재정의할 수 있습니다. 하지만 이 패턴을 사용하면 코드가 복잡해질 수 있으므로, 실제로 알고리즘의 특정 단계를 재정의해야 하는 경우에만 이 패턴을 사용하는 것이 좋습니다.