템플릿 메서드 패턴
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 94번째.
Template Method 패턴은 기본 타입에 algorithm의 뼈대를 정의하여, 전체 구조를 변경하지 않고도 하위 타입이 특정 단계를 재정의할 수 있도록 합니다. Decorator가 객체를 래핑하여 동작을 추가하는 반면, Template Method는 algorithm의 흐름을 제어하고 개별 단계를 사용자 지정할 수 있도록 합니다.
Go에는 상속이 없으므로 구조체 임베딩과 인터페이스를 결합하여 이 패턴을 구현합니다. "템플릿" 구조체는 algorithm의 구조를 정의하고 사용자 지정할 수 있는 methods를 호출합니다:
type DataProcessor interface {
ReadData() string
ProcessData(data string) string
SaveData(result string) string
}
type BaseProcessor struct {
Impl DataProcessor
}
func (b *BaseProcessor) Execute() string {
data := b.Impl.ReadData()
result := b.Impl.ProcessData(data)
return b.Impl.SaveData(result)
}구체적인 구현은 각 단계의 자체 버전을 제공하지만 알고리즘 흐름은 변경되지 않습니다:
type CSVProcessor struct{}
func (c CSVProcessor) ReadData() string { return "csv-data" }
func (c CSVProcessor) ProcessData(d string) string { return "processed-" + d }
func (c CSVProcessor) SaveData(r string) string { return "Saved: " + r }
type JSONProcessor struct{}
func (j JSONProcessor) ReadData() string { return "json-data" }
func (j JSONProcessor) ProcessData(d string) string { return "parsed-" + d }
func (j JSONProcessor) SaveData(r string) string { return "Stored: " + r }템플릿 method Execute는 단계를 고정된 순서로 orchestrates합니다:
csvProc := &BaseProcessor{Impl: CSVProcessor{}}
fmt.Println(csvProc.Execute()) // 저장됨: processed-csv-data
jsonProc := &BaseProcessor{Impl: JSONProcessor{}}
fmt.Println(jsonProc.Execute()) // 저장됨: parsed-json-dataTemplate Method는 동일한 구조를 공유하지만 특정 단계가 서로 다른 알고리즘에 이상적입니다. 예를 들어 data import/export 파이프라인, 리포트 생성기 또는 테스트 프레임워크가 있습니다.
챌린지
쉬움Template Method 패턴을 사용하여 보고서 generation 시스템을 구축해 봅시다! 서로 다른 보고서 유형이 동일한 generation 프로세스를 따르도록 framework를 만들 것입니다. 즉, data를 수집하고, 형식을 지정하고, 결과를 출력하지만 각 보고서 유형은 이러한 단계를 서로 다르게 사용자 지정합니다.
코드를 세 개의 파일로 구성합니다.
report.go: interface와 보고서 generation algorithm을 orchestrates하는 기본 processor를 Define합니다.보고서 generation의 단계를 나타내는 세 가지 methods를 가진
ReportGeneratorinterface를 Create합니다.GatherData() string: 보고서의 원시 data를 가져옵니다.FormatData(data string) string: data를 보고서의 형식으로 변환합니다.OutputReport(formatted string) string: final 출력 메시지를 생성합니다.
ReportGenerator구현을 holds하는ReportProcessorstruct를 Build합니다. 세 단계를 순서대로, 즉 gather, format, 그리고 output 순서로 executes하여 final 결과를 반환하는Generate() stringmethod를 추가합니다.generators.go: 각 단계를 사용자 지정하는 구체적인 보고서 generator를 Implement합니다.두 가지 보고서 유형을 Create합니다.
SalesReport와Regionfield (string)GatherData()는sales-data-[region]을 반환합니다.FormatData(data)는SALES REPORT: [data]를 반환합니다.OutputReport(formatted)는Printed: [formatted]를 반환합니다.
InventoryReport와Warehousefield (string)GatherData()는inventory-[warehouse]를 반환합니다.FormatData(data)는*** [data] ***를 반환합니다.OutputReport(formatted)는Exported: [formatted]를 반환합니다.
main.go: 동일한 algorithm 구조가 구현에 따라 서로 다른 결과를 생성하는 방식을 Demonstrate합니다.보고서 유형(
sales또는inventory)과 configuration 값(sales인 경우 region,inventory인 경우 warehouse)을 읽습니다. appropriate generator를 Create하고, 이를ReportProcessor로 감싼 다음Generate()를 Call하고 결과를 print합니다.
다음 입력이 제공됩니다.
- 1번 줄: 보고서 유형(
sales또는inventory) - 2번 줄: configuration 값(region 이름 또는 warehouse 이름)
예를 들어 다음이 주어졌을 때:
sales
North출력은 다음과 같아야 합니다.
Printed: SALES REPORT: sales-data-North그리고 다음이 주어졌을 때:
inventory
MainHub출력은 다음과 같아야 합니다.
Exported: *** inventory-MainHub ***그리고 다음이 주어졌을 때:
sales
West출력은 다음과 같아야 합니다.
Printed: SALES REPORT: sales-data-WestReportProcessor가 항상 동일한 세 단계를 동일한 순서로 Call하지만, 각 보고서 유형은 이러한 단계에 대한 자체 구현을 제공한다는 점에 주목하세요. algorithm의 골격은 고정된 채 세부 사항만 달라집니다. 이것이 바로 Template Method 패턴의 동작 방식입니다!
직접 해보기
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// 보고서 유형 읽기
scanner.Scan()
reportType := scanner.Text()
// 구성 값 읽기 (지역 또는 창고)
scanner.Scan()
configValue := scanner.Text()
// TODO: reportType에 따라 적절한 generator 생성
// - reportType이 "sales"인 경우, Region을 configValue로 설정한 SalesReport 생성
// - reportType이 "inventory"인 경우, Warehouse를 configValue로 설정한 InventoryReport 생성
// TODO: generator로 ReportProcessor 생성
// TODO: Generate()를 호출하고 결과 출력
_ = reportType
_ = configValue
fmt.Println("TODO: Generate and print the report")
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서직접 연습해 보세요: 온라인 Go 컴파일러