템플릿 메서드 패턴
Coddy C# 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 70개 중 59번째.
템플릿 메서드 패턴(Template Method pattern)은 알고리즘의 구조를 기본 클래스에서 정의하고, 전체적인 구조를 변경하지 않으면서 하위 클래스에서 특정 단계를 오버라이드할 수 있도록 하는 행동 패턴입니다. 기본 클래스가 워크플로우를 제어하며, 파생 클래스는 개별 단계를 커스터마이징합니다.
이 패턴은 상속과 추상 메서드를 사용합니다. 기본 클래스에는 일련의 단계를 호출하는 "템플릿 메서드"가 포함되어 있으며, 그 중 일부는 추상적이며 하위 클래스에서 구현되어야 합니다:
public abstract class DataProcessor
{
// 템플릿 메서드 - 알고리즘 구조를 정의합니다
public void Process()
{
ReadData();
ProcessData();
SaveData();
}
protected abstract void ReadData();
protected abstract void ProcessData();
protected virtual void SaveData() => Console.WriteLine("Saving to default location");
}
public class CsvProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Reading CSV file");
protected override void ProcessData() => Console.WriteLine("Parsing CSV data");
}
public class JsonProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Reading JSON file");
protected override void ProcessData() => Console.WriteLine("Parsing JSON data");
protected override void SaveData() => Console.WriteLine("Saving to cloud");
}각 서브클래스는 자체적인 구현을 제공하는 한편, 베이스 클래스는 작업 순서를 강제합니다:
DataProcessor csv = new CsvProcessor();
csv.Process();
// CSV 파일 읽기
// CSV 데이터 파싱하기
// 기본 위치에 저장하기
DataProcessor json = new JsonProcessor();
json.Process();
// JSON 파일 읽기
// JSON 데이터 파싱하기
// 클라우드에 저장하기템플릿 메서드 패턴은 여러 클래스가 동일한 알고리즘 구조를 공유하지만 특정 단계에서 차이가 있을 때 사용하기 이상적입니다. 이 패턴은 공통 로직을 기본 클래스에 배치하여 코드 재사용을 촉진하는 동시에, 오버라이드 가능한 메서드를 통해 유연성을 제공합니다.
챌린지
쉬움템플릿 메서드(Template Method) 패턴을 사용하여 보고서 생성 시스템을 구축해 보겠습니다. 다양한 유형의 보고서(예: 판매 보고서 및 재고 보고서)는 동일한 전체 구조를 공유합니다. 즉, 모두 데이터를 수집하고, 형식을 지정하고, 결과를 출력해야 하지만, 각 보고서 유형마다 이러한 단계를 처리하는 방식이 다릅니다.
코드는 다음 세 개의 파일로 구성됩니다:
ReportGenerator.cs:Reporting네임스페이스에 추상 클래스인ReportGenerator를 생성합니다. 이 기본 클래스는Generate()라는 템플릿 메서드를 통해 보고서 생성 알고리즘의 골격을 정의합니다. 이 메서드는GatherData(),FormatReport(),OutputReport()의 세 단계를 순서대로 호출해야 합니다.GatherData()와FormatReport()는 추상 메서드로 만들어 각 보고서 유형이 다르게 구현하도록 하고,OutputReport()는Sending to default printer를 출력하는 기본 구현을 가진 가상(virtual) 메서드로 만듭니다.ConcreteReports.cs:ReportGenerator를 상속받는 두 개의 구체적인 보고서 클래스를 동일한 네임스페이스에 생성합니다:SalesReport-GatherData()를 구현하여Collecting sales data from database를 출력하고,FormatReport()를 구현하여Formatting as sales summary를 출력합니다.InventoryReport-GatherData()를 구현하여Scanning warehouse inventory를 출력하고,FormatReport()를 구현하여Formatting as inventory list를 출력하며,OutputReport()를 오버라이드하여Sending to warehouse manager를 출력합니다.
Program.cs: 보고서 인스턴스를 생성하고 실행하여 모든 것을 하나로 묶습니다. 템플릿 메서드는 각 보고서가 동일한 3단계 프로세스를 따르도록 보장하지만, 각 단계의 구체적인 동작은 보고서 유형에 따라 달라집니다.
하나의 입력을 받게 됩니다:
- 보고서 유형:
sales또는inventory
입력에 따라 적절한 보고서 생성기를 생성하고 해당 Generate() 메서드를 호출하세요.
예를 들어, 입력이 sales인 경우 출력은 다음과 같아야 합니다:
Collecting sales data from database
Formatting as sales summary
Sending to default printer입력이 inventory인 경우 출력은 다음과 같아야 합니다:
Scanning warehouse inventory
Formatting as inventory list
Sending to warehouse manager두 보고서가 정확히 동일한 알고리즘 구조(수집, 형식 지정, 출력)를 따르지만 각 단계의 구현이 어떻게 맞춤화되었는지 확인해 보세요. SalesReport는 기본 출력 동작을 사용하고 InventoryReport는 이를 오버라이드합니다. 이는 템플릿 메서드 패턴을 통해 어떤 단계가 필수적으로 오버라이드되어야 하는지, 어떤 단계가 선택적으로 맞춤화될 수 있는지를 어떻게 제어할 수 있는지 보여줍니다!
직접 해보기
using System;
using Reporting;
class Program
{
public static void Main(string[] args)
{
string reportType = Console.ReadLine();
// TODO: reportType에 따라 적절한 보고서 생성기를 만드세요
// reportType이 "sales"인 경우, SalesReport를 생성하세요
// reportType이 "inventory"인 경우, InventoryReport를 생성하세요
// 그런 다음 보고서에서 Generate() 메서드를 호출하세요
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.