Menu
Coddy logo textTech

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] HELLO

Decorator, 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.

challenge icon

Görev

Kolay

Decorator 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 Beverage arayüzü oluştur:

    • Description() string: içeceğin ne olduğunu döndürür
    • Cost() float64: fiyatı döndürür

    Temel içecek olarak bir Coffee struct'ı uygula. Açıklaması Coffee, maliyeti ise 2.00 olmalıdır.

  • decorators.go: Herhangi bir içeceğe ekstralar ekleyen decorator türlerini oluştur.

    Her decorator bir Beverage sarar ve aynı arayüzü uygular. Üç decorator oluştur:

    • MilkDecorator: açıklamaya , Milk, maliyete ise 0.50 ekler
    • SugarDecorator: açıklamaya , Sugar, maliyete ise 0.25 ekler
    • WhipDecorator: açıklamaya , Whip, maliyete ise 0.75 ekler

    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, sugar veya whip) 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.XX biç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, sugar veya whip)

Ö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.00

Her 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
}
quiz iconKendini test et

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

Kendi başına pratik yap: Online Go derleyicisi