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

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

challenge icon

Görev

Kolay

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

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

    Temel içeceğiniz olarak bir Coffee yapısı (struct) uygulayın. Açıklaması Coffee ve maliyeti 2.00 olmalıdır.

  • decorators.go: Herhangi bir içeceğe ekstra ekleyen dekoratör türlerinizi oluşturun.

    Her dekoratör bir Beverage sarmalar ve aynı arayüzü uygular. Üç dekoratör oluşturun:

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

    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, sugar veya whip) 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, sugar veya whip)

Örneğin, şu girdi verildiğinde:

2
milk
sugar

Çıktınız şöyle olmalıdır:

Coffee, Milk, Sugar
$2.75

Ve şu girdi verildiğinde:

3
whip
milk
milk

Çıktınız şöyle olmalıdır:

Coffee, Whip, Milk, Milk
$3.75

Ve şu girdi verildiğinde:

0

Çıktınız şöyle olmalıdır:

Coffee
$2.00

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

Nesne 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
}
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