Menu
Coddy logo textTech

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 ödendi

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

challenge icon

Görev

Kolay

Strategy 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) string metoduna sahip bir TextFormatter arayüzü oluşturun.

    Üç formatlama stratejisi uygulayın:

    • UppercaseFormatter — metni tamamen büyük harfe dönüştürür
    • SnakeCaseFormatter — boşlukları alt çizgiye dönüştürür ve metni küçük harf yapar
    • TitleFormatter — 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 TextFormatter stratejisi tutan bir TextProcessor yapı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.

  • 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, snake veya title) 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 Today

Ve şu girdi verildiğinde:

Go Programming Language
2
snake
upper

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

go_programming_language
GO PROGRAMMING LANGUAGE

Ve şu girdi verildiğinde:

design patterns are useful
1
title

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

Design Patterns Are Useful

Aynı 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 PayPal

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