데코레이터 패턴
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 93번째.
Decorator 패턴을 사용하면 객체를 다른 객체로 감싸 동적으로 새로운 동작을 추가할 수 있습니다. Adapter는 다른 인터페이스에 맞게 인터페이스를 변경하는 반면, Decorator는 동일한 인터페이스를 유지하면서 원래 객체 주위에 래퍼를 겹겹이 추가하여 기능을 향상합니다.
Go에서는 base 타입과 데코레이터가 모두 동일한 interface를 구현하도록 하여 이를 구현합니다:
type Notifier interface {
Send(message string) string
}
type BasicNotifier struct{}
func (b BasicNotifier) Send(message string) string {
return "Sending: " + message
}데코레이터는 다른 Notifier를 감싸고, 해당 객체에 위임하기 전이나 후에 동작을 추가합니다:
type TimestampDecorator struct {
wrapped Notifier
}
func (t TimestampDecorator) Send(message string) string {
timestamped := "[2024-01-15] " + message
return t.wrapped.Send(timestamped)
}
type UppercaseDecorator struct {
wrapped Notifier
}
func (u UppercaseDecorator) Send(message string) string {
return strings.ToUpper(u.wrapped.Send(message))
}Decorator의 강력함은 여러 래퍼를 쌓아 동작을 결합하는 데 있습니다:
notifier := BasicNotifier{}
withTimestamp := TimestampDecorator{wrapped: notifier}
withBoth := UppercaseDecorator{wrapped: withTimestamp}
fmt.Println(notifier.Send("Hello"))
// 전송: Hello
fmt.Println(withBoth.Send("Hello"))
// 전송: [2024-01-15] HELLODecorator는 코드를 수정하지 않고 객체에 책임을 추가해야 할 때 이상적이며, 특히 다양한 기능 조합이 필요할 때 유용합니다. 일반적으로 logging, 캐싱, 인증 및 압축 계층에 사용됩니다.
챌린지
쉬움Decorator 패턴을 사용하여 커피숍 주문 시스템을 만들어 봅시다! base 커피 음료와 milk, sugar, whipped cream 같은 extra를 추가하는 decorator를 만들게 됩니다. 각 decorator는 이전 decorator를 감싸 description과 가격을 함께 구성합니다. decorator가 기능을 계층적으로 추가하는 방식을 보여 주는 완벽한 실전 예제입니다.
코드를 세 개의 파일로 구성합니다:
beverage.go: 핵심 interface와 base 커피 타입을 Define합니다.다음 두 methods를 가진
Beverageinterface를 만드세요:Description() string: drink가 무엇인지 반환합니다Cost() float64: 가격을 반환합니다
base beverage로
Coffeestruct를 Implement하세요. description은Coffee이고 cost는2.00이어야 합니다.decorators.go: 모든 beverage에 extra를 추가하는 decorator 타입을 만드세요.각 decorator는
Beverage를 감싸고 동일한 interface를 Implement합니다. 다음 세 decorator를 만드세요:MilkDecorator: description에, Milk를 추가하고 cost에0.50을 추가합니다SugarDecorator: description에, Sugar를 추가하고 cost에0.25를 추가합니다WhipDecorator: description에, Whip을 추가하고 cost에0.75를 추가합니다
각 decorator는 감싼 beverage의 methods를 호출하고 그 결과를 확장해야 합니다.
main.go: decorator를 쌓아 customized drink를 만드세요.추가할 extra의 count를 읽습니다. 그런 다음 각 extra에 대해 그 타입(
milk,sugar또는whip)을 읽고, 현재 beverage를 적절한 decorator로 감쌉니다.모든 extra를 적용한 후 최종 drink의 description과 cost를 각각 별도의 줄에 출력합니다. cost는 소수점 이하 정확히 두 자리인
$X.XX형식으로 Format하세요.
다음 입력이 제공됩니다:
- 1번째 줄: 추가할 extra의 수
- 이후 줄: 줄마다 하나의 extra 타입(
milk,sugar또는whip)
예를 들어 다음이 주어지면:
2
milk
sugar출력은 다음과 같아야 합니다:
Coffee, Milk, Sugar
$2.75또한 다음이 주어지면:
3
whip
milk
milk출력은 다음과 같아야 합니다:
Coffee, Whip, Milk, Milk
$3.75또한 다음이 주어지면:
0출력은 다음과 같아야 합니다:
Coffee
$2.00각 decorator가 이전 beverage를 감싸 description과 cost를 함께 구성하는 방식에 주목하세요. 동일한 extra를 여러 번 추가할 수 있으며(예: double milk), decorator의 순서가 description에 나타나는 순서를 결정합니다. base coffee는 extra에 대해 아무것도 알지 못합니다. 각 decorator는 자신이 감싸는 대상에 단순히 기능을 추가할 뿐입니다!
직접 해보기
package main
import (
"fmt"
)
func main() {
// 추가 항목의 개수를 읽습니다
var count int
fmt.Scanln(&count)
// 기본 커피로 시작합니다
var drink Beverage = &Coffee{}
// 각 추가 항목을 읽고 적절한 데코레이터로 drink를 감쌉니다
for i := 0; i < count; i++ {
var extra string
fmt.Scanln(&extra)
// TODO: 추가 항목 유형에 따라 적절한 데코레이터로 drink를 감싸세요
// "milk"에는 MilkDecorator를 사용합니다
// "sugar"에는 SugarDecorator를 사용합니다
// "whip"에는 WhipDecorator를 사용합니다
}
// TODO: 최종 설명과 비용을 출력합니다
// 비용을 정확히 소수점 두 자리의 $X.XX 형식으로 포맷합니다
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서직접 연습해 보세요: 온라인 Go 컴파일러