Dekoratör Kalıbı
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 93 / 107.
Decorator deseni, nesneleri diğer nesnelerin içine sararak onlara dinamik olarak yeni davranışlar eklemenize olanak tanır. Adapter bir arayüzü diğerine uyacak şekilde değiştirirken, Decorator aynı arayüzü korur ancak orijinal nesnenin etrafına sarmalayıcılar katmanlayarak işlevselliği artırır.
Go'da bunu, hem temel türün hem de dekoratörlerin aynı arayüzü uygulamasını sağlayarak gerçekleştiririz:
type Notifier interface {
Send(message string) string
}
type BasicNotifier struct{}
func (b BasicNotifier) Send(message string) string {
return "Sending: " + message
}Dekoratörler başka bir Notifier'ı sarmalar ve ona devretmeden önce veya sonra davranış ekler:
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'ın gücü, davranışları birleştirmek için birden fazla sarmalayıcıyı üst üste eklemekte yatar:
notifier := BasicNotifier{}
withTimestamp := TimestampDecorator{wrapped: notifier}
withBoth := UppercaseDecorator{wrapped: withTimestamp}
fmt.Println(notifier.Send("Hello"))
// Gönderiliyor: Hello
fmt.Println(withBoth.Send("Hello"))
// GÖNDERİLİYOR: [2024-01-15] HELLODecorator, nesnelerin kodlarını değiştirmeden onlara sorumluluklar eklemeniz gerektiğinde, özellikle de farklı özellik kombinasyonlarına ihtiyaç duyulduğunda idealdir. Genellikle günlükleme, önbelleğe alma, kimlik doğrulama ve sıkıştırma katmanları için kullanılır.
Görev
KolayDecorator desenini kullanarak bir kahve dükkanı sipariş sistemi oluşturalım! Temel bir kahve içeceği ve süt, şeker ve krem şanti gibi ekstralar ekleyen dekoratörler oluşturacaksınız. Her dekoratör bir öncekini sarmalayarak hem açıklamayı hem de fiyatı oluşturur; bu, dekoratörlerin işlevselliği nasıl katmanlandırdığına dair mükemmel bir gerçek dünya örneğidir.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
beverage.go: Temel arayüzünüzü ve temel kahve türünüzü tanımlayın.İki yöntemi olan bir
Beveragearayüzü oluşturun:Description() string— içeceğin ne olduğunu döndürürCost() float64— fiyatı döndürür
Temel içeceğiniz olarak bir
Coffeeyapısı (struct) uygulayın. AçıklamasıCoffeeve maliyeti2.00olmalıdır.decorators.go: Herhangi bir içeceğe ekstra ekleyen dekoratör türlerinizi oluşturun.Her dekoratör bir
Beveragesarmalar ve aynı arayüzü uygular. Üç dekoratör oluşturun:MilkDecorator— açıklamaya, Milkve maliyete0.50eklerSugarDecorator— açıklamaya, Sugarve maliyete0.25eklerWhipDecorator— açıklamaya, Whipve maliyete0.75ekler
Her dekoratör, sarmalanmış içeceğin yöntemlerini çağırmalı ve sonucu geliştirmelidir.
main.go: Dekoratörleri üst üste ekleyerek özelleştirilmiş içecekler oluşturun.Eklenecek ekstra sayısını okuyun. Ardından her ekstra için türünü (
milk,sugarveyawhip) okuyun ve mevcut içeceğinizi uygun dekoratörle sarmalayın.Tüm ekstraları uyguladıktan sonra, son içeceğin açıklamasını ve maliyetini ayrı satırlara yazdırın. Maliyeti tam olarak iki ondalık basamakla
$X.XXşeklinde biçimlendirin.
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Eklenecek ekstra sayısı
- Sonraki satırlar: Satır başına bir ekstra türü (
milk,sugarveyawhip)
Örneğin, şu girdi verildiğinde:
2
milk
sugarÇıktınız şöyle olmalıdır:
Coffee, Milk, Sugar
$2.75Ve şu girdi verildiğinde:
3
whip
milk
milkÇıktınız şöyle olmalıdır:
Coffee, Whip, Milk, Milk
$3.75Ve şu girdi verildiğinde:
0Çıktınız şöyle olmalıdır:
Coffee
$2.00Her dekoratörün bir önceki içeceği nasıl sarmaladığına, hem açıklamayı hem de maliyeti nasıl oluşturduğuna dikkat edin. Aynı ekstradan birden fazla ekleyebilirsiniz (çift süt gibi) ve dekoratörlerin sırası açıklamadaki sırayı belirler. Temel kahve ekstralar hakkında hiçbir şey bilmez; her dekoratör sadece sarmaladığı şeyi geliştirir!
Kopya kağıdı
Decorator deseni, nesneleri diğer nesnelerin içine sararak onlara dinamik olarak yeni davranışlar ekler. Aynı arayüzü korur ancak katmanlama yoluyla işlevselliği artırır.
Hem temel tür hem de dekoratörler aynı arayüzü uygular:
type Notifier interface {
Send(message string) string
}
type BasicNotifier struct{}
func (b BasicNotifier) Send(message string) string {
return "Sending: " + message
}Dekoratörler başka bir nesneyi sarar ve yetki devretmeden önce veya sonra davranış ekler:
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))
}Davranışları birleştirmek için birden fazla dekoratörü üst üste ekleyin:
notifier := BasicNotifier{}
withTimestamp := TimestampDecorator{wrapped: notifier}
withBoth := UppercaseDecorator{wrapped: withTimestamp}
fmt.Println(notifier.Send("Hello"))
// Sending: Hello
fmt.Println(withBoth.Send("Hello"))
// SENDING: [2024-01-15] HELLONesne kodunu değiştirmeden, özellikle farklı özellik kombinasyonları için sorumluluklar eklemek amacıyla Decorator desenini kullanın. Yaygın kullanımlar: günlükleme (logging), önbelleğe alma (caching), kimlik doğrulama (authentication), sıkıştırma (compression).
Kendin dene
package main
import (
"fmt"
)
func main() {
// Ekstraların sayısını oku
var count int
fmt.Scanln(&count)
// Temel bir kahve ile başla
var drink Beverage = &Coffee{}
// Her bir ekstrayı oku ve içeceği uygun dekoratör ile sarmala
for i := 0; i < count; i++ {
var extra string
fmt.Scanln(&extra)
// TODO: Ekstra türüne bağlı olarak, içeceği uygun dekoratör ile sarmala
// "milk" için MilkDecorator kullanın
// "sugar" için SugarDecorator kullanın
// "whip" için WhipDecorator kullanın
}
// TODO: Nihai açıklamayı ve maliyeti yazdır
// Maliyeti tam olarak iki ondalık basamakla $X.XX şeklinde biçimlendirin
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı11Standart Kütüphane ve OOP
io.Reader ve io.Writersort.Interface Arayüzüfmt.Stringer ArayüzüStruct'lar ile encoding/jsonhttp.Handler ArayüzüÖzet - REST API Modelleri14Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıDekoratör olarak Middleware3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker Pool