Strategy Kalıbı
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 90 / 107.
Strateji deseni (Strategy pattern), bir algoritma ailesi tanımlamanıza, her birini kapsüllemenize ve bunları çalışma zamanında birbirinin yerine kullanılabilir hale getirmenize olanak tanır. Birden fazla nesnenin tek bir olaya tepki verdiği Observer deseninin aksine Strategy, tek bir nesnenin farklı davranışlar arasında dinamik olarak geçiş yapmasını sağlar.
Go'da, algoritma için bir arayüz tanımlayarak ve farklı uygulamaları bir context yapısına (struct) enjekte ederek Strategy desenini uygularız:
type PaymentStrategy interface {
Pay(amount float64) string
}
type CreditCard struct{}
func (c CreditCard) Pay(amount float64) string {
return fmt.Sprintf("Paid %.2f via Credit Card", amount)
}
type PayPal struct{}
func (p PayPal) Pay(amount float64) string {
return fmt.Sprintf("Paid %.2f via PayPal", amount)
}Context yapısı, strateji arayüzüne (strategy interface) bir referans tutar ve bu da context kodunu değiştirmeden algoritmanın değiştirilmesine olanak tanır:
type Checkout struct {
strategy PaymentStrategy
}
func (c *Checkout) SetStrategy(s PaymentStrategy) {
c.strategy = s
}
func (c *Checkout) ProcessPayment(amount float64) string {
return c.strategy.Pay(amount)
}Artık ödeme yöntemini çalışma zamanında değiştirebilirsiniz:
checkout := &Checkout{}
checkout.SetStrategy(CreditCard{})
fmt.Println(checkout.ProcessPayment(100.00)) // Kredi Kartı ile 100.00 ödendi
checkout.SetStrategy(PayPal{})
fmt.Println(checkout.ProcessPayment(50.00)) // PayPal ile 50.00 ödendiStrateji, bir işlemi gerçekleştirmek için birden fazla yolunuz olduğunda ve kullanıcı girişi, yapılandırma veya çalışma zamanı koşullarına bağlı olarak bunlardan birini seçmeniz gerektiğinde idealdir. Yaygın kullanım durumları arasında sıralama algoritmaları, sıkıştırma yöntemleri ve doğrulama kuralları yer alır.
Görev
KolayStrategy desenini kullanarak bir metin formatlama sistemi oluşturalım! Çalışma zamanında değiştirilebilen farklı formatlama stratejileri oluşturacaksınız; bu sayede aynı metin işlemcisinin, çekirdek kodunu değiştirmeden farklı çıktı stilleri üretmesini sağlayacaksınız.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
formatter.go: Strateji arayüzünüzü (interface) ve somut formatlama stratejilerinizi tanımlayın.Metni stratejinin kurallarına göre dönüştüren
Format(text string) stringmetoduna sahip birTextFormatterarayüzü oluşturun.Üç formatlama stratejisi uygulayın:
UppercaseFormatter— metni tamamen büyük harfe dönüştürürSnakeCaseFormatter— boşlukları alt çizgiye dönüştürür ve metni küçük harf yaparTitleFormatter— her kelimenin ilk harfini büyük yapar (kelimeler boşluklarla ayrılır)
processor.go: Formatlama stratejisini kullanan bağlam (context) yapınızı oluşturun.Bir
TextFormatterstratejisi tutan birTextProcessoryapısı oluşturun. Şu metodları ekleyin:- Aktif formatlama stratejisini değiştirmek için
SetFormatter(f TextFormatter) - Mevcut formatlayıcıyı metne uygulayan
Process(text string) string
Ayrıca, başlangıçta herhangi bir formatlayıcı atanmamış bir işlemci döndüren bir
NewTextProcessor()yapıcı fonksiyonu (constructor) oluşturun.- Aktif formatlama stratejisini değiştirmek için
main.go: Stratejilerin çalışma zamanında değiştirilmesini gösterin.Bir metin parçası okuyun, ardından formatlama işlemi sayısını okuyun. Her işlem için format türünü (
upper,snakeveyatitle) okuyun, işlemcinize uygun formatlayıcıyı ayarlayın, orijinal metni işleyin ve sonucu yazdırın.
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Formatlanacak metin
- Satır 2: Formatlama işlemi sayısı
- Sonraki satırlar: Her işlem için format türü
Örneğin, şu girdi verildiğinde:
hello world today
3
upper
snake
titleÇıktınız şöyle olmalıdır:
HELLO WORLD TODAY
hello_world_today
Hello World TodayVe şu girdi verildiğinde:
Go Programming Language
2
snake
upperÇıktınız şöyle olmalıdır:
go_programming_language
GO PROGRAMMING LANGUAGEVe şu girdi verildiğinde:
design patterns are useful
1
titleÇıktınız şöyle olmalıdır:
Design Patterns Are UsefulAynı TextProcessor yapısının, sadece formatlayıcı stratejisini değiştirerek nasıl tamamen farklı çıktılar ürettiğine dikkat edin. İşlemci, hangi özel formatlayıcıyı kullandığını bilmez veya umursamaz; sadece o an ayarlanmış olan stratejiye görevi devreder!
Kopya kağıdı
Strateji deseni (Strategy pattern), bir algoritma ailesi tanımlar, her birini kapsüller ve çalışma zamanında birbirlerinin yerine kullanılabilir hale getirir. Tek bir nesnenin farklı davranışlar arasında dinamik olarak geçiş yapmasına olanak tanır.
Algoritma için bir arayüz (interface) tanımlayın:
type PaymentStrategy interface {
Pay(amount float64) string
}Somut stratejileri uygulayın:
type CreditCard struct{}
func (c CreditCard) Pay(amount float64) string {
return fmt.Sprintf("Paid %.2f via Credit Card", amount)
}
type PayPal struct{}
func (p PayPal) Pay(amount float64) string {
return fmt.Sprintf("Paid %.2f via PayPal", amount)
}Strateji arayüzüne bir referans tutan bir bağlam (context) yapısı (struct) oluşturun:
type Checkout struct {
strategy PaymentStrategy
}
func (c *Checkout) SetStrategy(s PaymentStrategy) {
c.strategy = s
}
func (c *Checkout) ProcessPayment(amount float64) string {
return c.strategy.Pay(amount)
}Çalışma zamanında stratejileri değiştirin:
checkout := &Checkout{}
checkout.SetStrategy(CreditCard{})
fmt.Println(checkout.ProcessPayment(100.00)) // Paid 100.00 via Credit Card
checkout.SetStrategy(PayPal{})
fmt.Println(checkout.ProcessPayment(50.00)) // Paid 50.00 via PayPalStrateji deseni, bir işlemi gerçekleştirmek için birden fazla yolunuz olduğunda ve kullanıcı girişi, yapılandırma veya çalışma zamanı koşullarına göre birini seçmeniz gerektiğinde idealdir.
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Formatlanacak metni oku
text, _ := reader.ReadString('\n')
text = strings.TrimSpace(text)
// İşlem sayısını oku
countStr, _ := reader.ReadString('\n')
count, _ := strconv.Atoi(strings.TrimSpace(countStr))
// Yeni bir metin işlemci oluştur
processor := NewTextProcessor()
// Her bir formatlama işlemini işle
for i := 0; i < count; i++ {
formatType, _ := reader.ReadString('\n')
formatType = strings.TrimSpace(formatType)
// TODO: formatType'a göre ("upper", "snake" veya "title"),
// işlemci üzerinde uygun formatlayıcıyı ayarla
// ve işlenmiş metni yazdır
}
}
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ı3İş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