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 başka nesnelerle sararak bunlara dinamik olarak yeni davranışlar eklemenizi sağlar. Adapter bir arayüzü başka bir arayüzle eşleşecek şekilde değiştirirken Decorator aynı arayüzü korur, ancak özgün nesnenin etrafına katmanlar hâlinde sarmalayıcılar ekleyerek işlevselliği geliştirir.
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'ı sarar ve çağrıyı ona devretmeden önce veya devrettikten 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. Günlük kaydı, önbelleğe alma, kimlik doğrulama ve sıkıştırma katmanları için yaygın olarak kullanılır.
Görev
KolayDecorator kalıbını kullanarak bir kahve dükkânı sipariş sistemi oluşturalım! Temel bir kahve içeceği ve süt, şeker ve krem şanti gibi ekstralar ekleyen decorator'lar oluşturacaksın. Her decorator, önceki decorator'ı sararak hem açıklamayı hem de fiyatı oluşturur: decorator'ların işlevselliği katmanlandırmasını gösteren mükemmel bir gerçek dünya örneği.
Kodunu üç dosyaya ayıracaksın:
beverage.go: Temel arayüzünü ve temel kahve türünü tanımla.İki metoda sahip bir
Beveragearayüzü oluştur:Description() string: içeceğin ne olduğunu döndürürCost() float64: fiyatı döndürür
Temel içecek olarak bir
Coffeestruct'ı uygula. AçıklamasıCoffee, maliyeti ise2.00olmalıdır.decorators.go: Herhangi bir içeceğe ekstralar ekleyen decorator türlerini oluştur.Her decorator bir
Beveragesarar ve aynı arayüzü uygular. Üç decorator oluştur:MilkDecorator: açıklamaya, Milk, maliyete ise0.50eklerSugarDecorator: açıklamaya, Sugar, maliyete ise0.25eklerWhipDecorator: açıklamaya, Whip, maliyete ise0.75ekler
Her decorator, sardığı içeceğin metotlarını çağırmalı ve sonucu geliştirmelidir.
main.go: Decorator'ları üst üste ekleyerek özelleştirilmiş içecekler oluştur.Eklenecek ekstraların sayısını oku. Ardından her ekstra için türünü (
milk,sugarveyawhip) oku ve mevcut içeceğini uygun decorator ile sar.Tüm ekstraları uyguladıktan sonra son içeceğin açıklamasını ve maliyetini ayrı satırlarda yazdır. Maliyeti tam iki ondalık basamakla
$X.XXbiçiminde biçimlendir.
Aşağıdaki girdiler sağlanacaktır:
- 1. satır: Eklenecek ekstraların sayısı
- Sonraki satırlar: Her satırda bir ekstra türü (
milk,sugarveyawhip)
Örneğin, şu girdi verildiğinde:
2
milk
sugarÇıktın şu olmalıdır:
Coffee, Milk, Sugar
$2.75Şu girdi verildiğinde:
3
whip
milk
milkÇıktın şu olmalıdır:
Coffee, Whip, Milk, Milk
$3.75Şu girdi verildiğinde:
0Çıktın şu olmalıdır:
Coffee
$2.00Her decorator'ın önceki içeceği nasıl sardığına ve hem açıklamayı hem de maliyeti oluşturduğuna dikkat et. Aynı ekstrayı birden fazla kez ekleyebilirsin (çift süt gibi) ve decorator'ların sırası, açıklamadaki sırayı belirler. Temel kahve ekstralar hakkında hiçbir şey bilmez: her decorator, yalnızca sardığı şeyi geliştirir!
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 ekstrayı oku ve içeceği uygun dekoratörle sar
for i := 0; i < count; i++ {
var extra string
fmt.Scanln(&extra)
// TODO: Ekstra türüne göre, drink'i uygun dekoratörle sar
// "milk" için MilkDecorator kullan
// "sugar" için SugarDecorator kullan
// "whip" için WhipDecorator kullan
}
// TODO: Son açıklamayı ve maliyeti yazdır
// Maliyeti tam olarak iki ondalık basamakla $X.XX olarak biçimlendir
}
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 PoolKendi başına pratik yap: Online Go derleyicisi