Menu
Coddy logo textTech

템플릿 메서드 패턴

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 99번째.

Template Method 패턴은 기반 클래스에서 algorithm의 뼈대를 정의하고, 하위 클래스가 algorithm의 전체 구조를 변경하지 않고 특정 단계를 재정의할 수 있도록 합니다. 전체 algorithm을 교체하는 Strategy와 달리, Template Method는 algorithm을 고정하면서 개별 단계를 사용자 지정할 수 있게 합니다.

base class는 템플릿 method(algorithm)를 구현하고, 서브클래스가 제공해야 하는 abstract 또는 virtual method를 호출합니다:

#include <iostream>

class DataProcessor {
public:
    // 템플릿 메서드 - 알고리즘 골격을 정의함
    void process() {
        loadData();
        processData();
        saveResults();
    }
    
    virtual ~DataProcessor() = default;
    
protected:
    virtual void loadData() = 0;      // 반드시 구현해야 함
    virtual void processData() = 0;   // 반드시 구현해야 함
    
    // 훅 - 기본 동작이 있는 선택적 오버라이드
    virtual void saveResults() {
        std::cout << "Saving to default location\n";
    }
};

class CSVProcessor : public DataProcessor {
protected:
    void loadData() override {
        std::cout << "Loading CSV file\n";
    }
    void processData() override {
        std::cout << "Parsing CSV data\n";
    }
};

class JSONProcessor : public DataProcessor {
protected:
    void loadData() override {
        std::cout << "Loading JSON file\n";
    }
    void processData() override {
        std::cout << "Parsing JSON data\n";
    }
    void saveResults() override {
        std::cout << "Saving to cloud storage\n";
    }
};

int main() {
    CSVProcessor csv;
    csv.process();  // 기본 saveResults 사용
    
    JSONProcessor json;
    json.process(); // 사용자 정의 saveResults 사용
}

process() 메서드는 템플릿 메서드로, 고정된 단계 순서를 정의합니다. 하위 클래스는 loadData()processData()를 서로 다르게 구현하지만, 순서는 절대 변경되지 않습니다. saveResults() 메서드는 "후크"로, 기본 구현을 제공하며 하위 클래스에서 선택적으로 재정의할 수 있습니다.

불변 단계로 구성된 algorithm이 있지만 특정 작업에서는 유연성이 필요할 때, 또는 유사한 클래스 간의 코드 중복을 피하고 싶을 때 Template Method를 사용하세요.

challenge icon

챌린지

쉬움

Template Method 패턴을 사용하여 Report Generator 시스템을 만들어 보겠습니다. 판매 보고서와 재고 보고서처럼 서로 다른 유형의 보고서가 동일한 생성 프로세스를 따르되, 각 보고서 유형이 특정 단계를 사용자 지정하는 프레임워크를 만들게 됩니다. 이는 Template Method를 적용하기에 완벽한 상황입니다. 전체 작업 흐름은 고정된 상태로 유지하면서 개별 단계는 달라질 수 있기 때문입니다.

코드를 세 개의 파일로 구성합니다.

  • ReportGenerator.h: template method를 포함하는 abstract base class를 정의합니다.

    보고서 생성 algorithm의 뼈대를 정의하는 ReportGenerator class를 만드세요. template method인 generateReport()는 다음 단계를 순서대로 실행해야 합니다.

    1. gatherData(): pure virtual이며, subclass에서 구현해야 합니다.
    2. formatReport(): pure virtual이며, subclass에서 구현해야 합니다.
    3. addHeader(): 기본 동작을 제공하는 Hook으로, --- Report ---를 출력합니다.
    4. printReport(): pure virtual이며, subclass에서 구현해야 합니다.

    addHeader() method는 subclass가 header를 사용자 지정하기 위해 선택적으로 재정의할 수 있는 Hook 역할을 합니다.

  • Reports.h: 두 개의 concrete report generator를 구현합니다.

    다음과 같은 SalesReport class를 만드세요.

    • gatherData()Gathering sales data from database를 출력합니다.
    • formatReport()Formatting sales figures를 출력합니다.
    • printReport()Sales Total: $[amount]를 출력하며, amount는 constructor에 전달됩니다.

    다음과 같은 InventoryReport class를 만드세요.

    • gatherData()Scanning inventory records를 출력합니다.
    • formatReport()Organizing inventory by category를 출력합니다.
    • addHeader()는 Hook을 재정의하여 === Inventory Report ===를 출력합니다.
    • printReport()Items in stock: [count]를 출력하며, count는 constructor에 전달됩니다.

    두 class는 각각의 값(amount 또는 count)을 constructor를 통해 받아야 합니다.

  • main.cpp: Template Method 패턴을 시연합니다.

    두 개의 입력을 읽습니다.

    1. 판매 금액(integer)
    2. 재고 수량(integer)

    판매 금액으로 SalesReport를 만들고 생성합니다. 그런 다음 재고 수량으로 InventoryReport를 만들고 생성합니다. 가독성을 위해 두 보고서 사이에 빈 줄을 출력합니다.

예를 들어 입력이 15000250인 경우:

Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $15000

Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 250

입력이 8500120인 경우:

Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $8500

Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 120

두 보고서가 모두 generateReport()에 정의된 정확히 동일한 단계 순서를 따르지만, 각 보고서가 해당 단계를 서로 다르게 구현한다는 점에 주목하세요. 또한 InventoryReport는 header를 사용자 지정하기 위해 Hook method를 재정의하는 예를 보여 주며, SalesReport는 기본 동작을 사용합니다. 이것이 바로 Template Method 패턴의 실제 동작입니다. algorithm 구조는 base class에 고정되어 있지만 세부 사항은 유연합니다.

직접 해보기

#include <iostream>
#include "Reports.h"

using namespace std;

int main() {
    // 입력 읽기
    int salesAmount;
    int inventoryCount;
    cin >> salesAmount;
    cin >> inventoryCount;
    
    // TODO: salesAmount로 SalesReport를 생성하고 생성하세요
    
    // TODO: 보고서 사이에 빈 줄을 출력하세요
    
    // TODO: Create an InventoryReport with inventoryCount and generate it
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 C++ 컴파일러