Menu
Coddy logo textTech

템플릿 메서드 패턴

Coddy PHP 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 91개 중 78번째.

템플릿 메서드 패턴(Template Method Pattern)은 알고리즘의 구조를 베이스 클래스에서 정의하고, 서브클래스에서 전체적인 구조를 변경하지 않고 특정 단계를 오버라이드할 수 있도록 하는 행동 디자인 패턴입니다. 베이스 클래스가 워크플로우를 제어하며, 서브클래스는 개별 단계를 커스터마이징합니다.

다양한 유형의 문서를 작성하는 것을 고려해 보세요.

모든 문서는 동일한 프로세스를 따릅니다: 헤더 생성, 콘텐츠 추가, 푸터 생성. 하지만 각 단계의 구체적인 내용은 문서 유형에 따라 다릅니다. 템플릿 메서드는 이 시퀀스를 정의하고, 서브클래스는 세부 사항을 구현합니다.

<?php
abstract class DocumentGenerator {
    // 템플릿 메서드 - 알고리즘 구조를 정의합니다.
    public final function generate(): string {
        $output = $this->createHeader();
        $output .= $this->createContent();
        $output .= $this->createFooter();
        return $output;
    }
    
    // 하위 클래스에서 구현해야 할 단계들
    abstract protected function createHeader(): string;
    abstract protected function createContent(): string;
    abstract protected function createFooter(): string;
}

class HtmlDocument extends DocumentGenerator {
    protected function createHeader(): string {
        return "<html><head></head><body>";
    }
    
    protected function createContent(): string {
        return "<p>Hello World</p>";
    }
    
    protected function createFooter(): string {
        return "</body></html>";
    }
}

class TextDocument extends DocumentGenerator {
    protected function createHeader(): string {
        return "=== DOCUMENT ===\n";
    }
    
    protected function createContent(): string {
        return "Hello World\n";
    }
    
    protected function createFooter(): string {
        return "=== END ===";
    }
}

$html = new HtmlDocument();
echo $html->generate() . "\n";

$text = new TextDocument();
echo $text->generate();

출력:

<html><head></head><body><p>Hello World</p></body></html>
=== DOCUMENT ===
Hello World
=== END ===

템플릿 메서드에 있는 final 키워드를 주목하세요. 이것은 하위 클래스가 알고리즘의 구조를 변경하는 것을 방지합니다. 이 패턴은 동일한 워크플로를 따르지만 구현 세부 사항이 다른 여러 클래스가 있을 때 이상적입니다. 새로운 문서 유형을 추가한다는 것은 기존 코드를 건드리지 않고 새로운 하위 클래스를 생성하는 것을 의미합니다.

challenge icon

챌린지

쉬움

템플릿 메서드 패턴(Template Method Pattern)을 사용하여 보고서 생성 시스템을 구축해 보겠습니다. 서로 다른 유형의 보고서라도 제목 섹션, 데이터 섹션, 요약 섹션이라는 동일한 구조를 따르지만, 각 보고서 유형마다 이러한 섹션을 다르게 형식화합니다. 템플릿 메서드는 이 워크플로우를 정의하고, 서브클래스는 각 단계를 커스터마이징합니다.

코드는 네 개의 파일로 구성됩니다:

  • ReportGenerator.php — 보고서 생성 알고리즘의 골격을 정의하는 추상 클래스 ReportGenerator를 생성합니다. 클래스는 다음을 수행해야 합니다:
    • 생성자에서 보고서 제목을 받습니다 (생성자 프로모션(constructor promotion)을 사용하세요)
    • createTitle(), createBody(), createSummary()의 세 단계를 순서대로 호출하고 그 결과를 연결하는 final 퍼블릭 메서드 generate(): string를 가집니다.
    • 서브클래스가 반드시 구현해야 하는 세 개의 추상 보호(protected) 메서드를 선언합니다: createTitle(): string, createBody(): string, createSummary(): string
  • HtmlReport.php — ReportGenerator 파일을 포함하고 이를 상속받는 HtmlReport 클래스를 생성합니다. 이 보고서는 출력을 HTML로 형식화합니다:
    • createTitle()"<h1>[title]</h1>"를 반환합니다.
    • createBody()"<p>Report data goes here</p>"를 반환합니다.
    • createSummary()"<footer>End of report</footer>"를 반환합니다.
  • PlainTextReport.php — ReportGenerator 파일을 포함하고 이를 상속받는 PlainTextReport 클래스를 생성합니다. 이 보고서는 단순 텍스트 형식을 사용합니다:
    • createTitle()"### [title] ###\n"를 반환합니다.
    • createBody()"Report data goes here\n"를 반환합니다.
    • createSummary()"--- End of report ---"를 반환합니다.
  • main.php — 두 보고서 파일을 모두 포함합니다. 보고서 유형("html" 또는 "text")과 보고서 제목이라는 두 개의 입력을 받습니다.

    보고서 유형에 따라 주어진 제목으로 적절한 보고서 생성기를 생성합니다. generate()를 호출하고 전체 보고서를 출력합니다.

템플릿 메서드 패턴은 모든 보고서가 동일한 3단계 구조를 따르도록 보장하는 동시에, 각 보고서 유형이 섹션을 고유하게 형식화할 수 있도록 허용합니다. generate() 메서드에 사용된 final 키워드는 서브클래스가 알고리즘의 순서를 변경하는 것을 방지하며, 서브클래스는 개별 단계만 커스터마이징할 수 있습니다.

치트 시트

템플릿 메서드 패턴(Template Method Pattern)은 알고리즘의 골격을 기본 클래스에서 정의하여, 서브클래스가 전체 구조를 변경하지 않고 특정 단계를 재정의할 수 있도록 합니다.

기본 클래스에는 워크플로 순서를 제어하는 템플릿 메서드가 포함되어 있습니다. 이 메서드는 일반적으로 서브클래스가 알고리즘의 구조를 변경하는 것을 방지하기 위해 final로 표시됩니다.

서브클래스는 알고리즘의 개별 단계를 사용자 정의하기 위해 추상 메서드를 구현합니다.

<?php
abstract class DocumentGenerator {
    // 템플릿 메서드 - 알고리즘 구조 정의
    public final function generate(): string {
        $output = $this->createHeader();
        $output .= $this->createContent();
        $output .= $this->createFooter();
        return $output;
    }
    
    // 서브클래스에서 구현할 추상 단계들
    abstract protected function createHeader(): string;
    abstract protected function createContent(): string;
    abstract protected function createFooter(): string;
}

class HtmlDocument extends DocumentGenerator {
    protected function createHeader(): string {
        return "<html><head></head><body>";
    }
    
    protected function createContent(): string {
        return "<p>Hello World</p>";
    }
    
    protected function createFooter(): string {
        return "</body></html>";
    }
}

$html = new HtmlDocument();
echo $html->generate();

주요 특징:

  • 알고리즘 구조의 수정을 방지하기 위해 템플릿 메서드는 final로 표시됩니다.
  • 추상 메서드는 서브클래스를 위한 사용자 정의 지점을 정의합니다.
  • 여러 클래스가 동일한 워크플로를 따르지만 구현 세부 사항이 다를 때 이상적입니다.
  • 새로운 변형을 추가할 때 기존 코드를 수정하지 않고 새로운 서브클래스만 생성하면 됩니다.

직접 해보기

<?php

require_once 'HtmlReport.php';
require_once 'PlainTextReport.php';

// 입력 읽기
$reportType = trim(fgets(STDIN));
$reportTitle = trim(fgets(STDIN));

// TODO: 보고서 유형("html" 또는 "text")에 따라,
// 주어진 제목으로 적절한 보고서 생성기를 만듭니다.

// TODO: generate()를 호출하고 전체 보고서를 출력합니다.

?>
quiz icon실력 점검

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

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