의도

  • 객체의 연산에는 알고리즘의 뼈대만을 정의하고 각 단계에서 수행할 구체적 처리는 서브클래스 쪽으로 미룸. 알고리즘의 구조 자체는 그대로 놔둔 채 알고리즘 각 단계 처리를 서브클래스에서 재정의할 수 있게 함.

 

언제 쓰는가 ?

  • 어떤 한 알고리즘을 이루는 부분 중 변하지 않는 부분을 한 번 정의해 놓고 다양해질 수 있는 부분은 서브클래스에서 정의할 수 있도록 남겨두고자 할 때
  • 서브클래스 사이의 공통적인 행동을 추출하여 하나의 공통 클래스에 몰아둠으로써 코드 중복을 피하고 싶을 때
  • 서브클래스의 확장을 제어할 수 있음. 템플릿 메서드가 어떤 특정한 시점에서 "훅" 연산을 호출하도록 정의함으로써, 그 특정 시점에서만 확장되도록 함

 

구조

GoF의 디자인 패턴 중 P.421

  • AbstractClass : 서브클래스들이 재정의를 통해 구현해야 하는 알고리즘 처리 단계 내의 기본 연산을 정의함. 그리고 알고리즘의 뼈대를 정의하는 메서드를 구현함. 템플릿 메서드는 AbstractClass에 정의된 연산 또는 다른 객체 연산뿐만 아니라 기본 연산도 호출함.
  • ConcreteClass : 서브클래스마다 달라진 알고리즘 처리 단계를 수행하기 위한 기본 연산을 구현함.

 

협력 방법

  • ConcreteClass는 AbstractClass를 통하여 알고리즘의 변하지 않는 처리 단계를 구현함.

 

결과

  • 코드 재사용을 위한 기본 기술
  • 훅 연산(오버라이드가 가능한지)과 추상 연산(꼭 오버라이드해야 하는지)를 지정해 두는 것이 굉장히 중요

 

구현 / 고려 사항

  1. C++의 접근 제한 방법 이용
    1. 템플릿 메서드에서 호출하는 연산들은 protected로 지정하면 좋음
    2. 오버라이드해야 하는 기본 연산은 반드시 순수 가상 함수로 정의
    3. 템플릿 메서드 자체는 재정의되면 안되므로 비가상 멤버 함수로 만듬
  2. 기본 연산의 수를 최소화
  3. 이름을 짓는 규칙을 만듬
    1. 재정의가 필요한 연산은 식별이 잘 되도록 접두사를 붙이는 것이 좋음. 어떤 응용프로그램은 Do이고 언리얼의 경우 On

 

예제 코드

  • 템플릿 메서드는 다양한 상황에 쓰이기에 특정 예를 들기보단 정확히 어떤 방법인지를 예제로 들었습니다.
#include "TemplateMethod1.h"

int main()
{
	DerivedTemplateMethod derived_templatemethod;

	derived_templatemethod.Activate();

	return 0;
}

  • 템플릿 메서드를 통해 고정된 문구 Start와 End를 만들어뒀고 상속을 통해 가상함수를 오버라이드하여 서브클래스마다 Start와 End 사이를 다르게 채울 수 있습니다.
//TemplateMethod1.h

#pragma once

class TemplateMethod
{
public:
	void Activate();

protected:
	virtual void OnActivate() = 0;
};

class DerivedTemplateMethod : public TemplateMethod
{
protected:
	virtual void OnActivate();
};
  • 템플릿 메서드의 전형적인 예시입니다. Activate는 비가상함수로 선언하여 재정의하지 않고, Activate 내에서 불리는 함수 OnActivate는 protected 지정자를 주어 외부에선 호출이 불가능하게 하고 자식 클래스에선 재정의가 가능하게 끔 만들어줍니다.
//TemplateMethod1.cpp

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

void TemplateMethod::Activate()
{
	std::cout << "템플릿 메서드 Activate Start !" << std::endl;

	OnActivate();

	std::cout << "템플릿 메서드 Activate End !" << std::endl;
}

void DerivedTemplateMethod::OnActivate()
{
	std::cout << "오버라이드를 통해 추상 연산을 재정의! " << std::endl;
	std::cout << "Activate는 비가상함수, Activate에서 불리는 OnActivate는 오버라이드하는 것이 템플릿 메서드 ! " << std::endl;
}
  • 앞서 언급한대로 Start와 End사이에 OnActivate 메서드를 호출하고 서브클래스마다 OnActivate를 다르게 정의하여 새로운 알고리즘을 정의합니다.

'디자인 패턴 > 행위' 카테고리의 다른 글

방문자(Visitor)  (0) 2024.01.15
전략(Strategy)  (0) 2024.01.15
상태(State)  (0) 2024.01.12
감시자(Observer)  (0) 2024.01.12
메멘토(Memento)  (1) 2024.01.11

+ Recent posts