Strategy Kalıbı
Coddy'nin C# Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 55 / 70.
Strateji deseni (Strategy pattern), bir algoritma ailesi tanımlamanıza, her birini kendi sınıfında kapsüllemenize ve bunları çalışma zamanında birbirinin yerine kullanılabilir hale getirmenize olanak tanıyan davranışsal bir desendir. Davranışı doğrudan kodun içine yazmak (hardcoding) yerine, istediğiniz stratejiyi bir nesneye enjekte edersiniz.
Desen üç bölümden oluşur: algoritma sözleşmesini tanımlayan bir strateji arayüzü, farklı davranışları uygulayan somut strateji sınıfları ve bir strateji kullanan bir bağlam sınıfı:
public interface IPaymentStrategy
{
void Pay(decimal amount);
}
public class CreditCardPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via Credit Card");
}
public class PayPalPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via PayPal");
}
public class ShoppingCart
{
private IPaymentStrategy _paymentStrategy;
public void SetPaymentMethod(IPaymentStrategy strategy)
{
_paymentStrategy = strategy;
}
public void Checkout(decimal total)
{
_paymentStrategy.Pay(total);
}
}Bağlam (ShoppingCart), hangi ödeme yöntemini kullandığını bilmez - sadece sağlanan strateji ne olursa olsun onun üzerindeki Pay() metodunu çağırır:
var cart = new ShoppingCart();
cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m); // Paid 99.99 via Credit Card
cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m); // Paid 49.99 via PayPalStrategy deseni karmaşık koşullu mantığı ortadan kaldırır. Yeni bir ödeme yöntemi eklemek, IPaymentStrategy arayüzünü uygulayan yeni bir sınıf oluşturmak anlamına gelir; ShoppingCart sınıfında herhangi bir değişiklik yapılmasına gerek kalmaz. Bu, kodunuzu genişletilmeye açık ancak değişikliğe kapalı hale getirir.
Görev
KolayStrateji (Strategy) desenini kullanarak bir nakliye maliyeti hesaplayıcı oluşturalım. Farklı nakliye yöntemlerinin farklı fiyatlandırma algoritmaları vardır ve sisteminiz, temel sipariş işleme mantığını değiştirmeden çalışma zamanında bunlar arasında geçiş yapılmasına izin vermelidir.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
ShippingStrategy.cs:Shippingad alanı (namespace) içinde,doubledöndüren birCalculateCost(double weight)metoduna sahip birIShippingStrategyarayüzü (interface) tanımlayın. Ardından üç somut strateji sınıfı oluşturun:StandardShipping- maliyetiweight * 1.5olarak hesaplarExpressShipping- maliyetiweight * 3.0 + 5.0olarak hesaplar (sabit bir ekspres ücreti içerir)OvernightShipping- maliyetiweight * 5.0 + 10.0olarak hesaplar (daha yüksek taban ücretli premium hizmet)
OrderProcessor.cs: Aynı ad alanında birOrderProcessorsınıfı oluşturun. Bu, bir nakliye stratejisi kullanan bağlam (context) sınıfınızdır. Şunlara sahip olmalıdır:- Mevcut
IShippingStrategynesnesini tutmak için özel (private) bir alan - Nakliye stratejisini değiştirmek için bir
SetShippingMethod(IShippingStrategy strategy)metodu - Nakliye maliyetini hesaplamak ve döndürmek için mevcut stratejiyi kullanan bir
ProcessOrder(double weight)metodu
- Mevcut
Program.cs: BirOrderProcessoroluşturarak ve nakliye stratejilerini çalışma zamanında nasıl değiştirebileceğinizi göstererek her şeyi bir araya getirin. Aynı işlemci, sadece stratejisini değiştirerek farklı algoritmalar kullanarak maliyetleri hesaplayabilir.
İki girdi alacaksınız:
- Nakliye yöntemi türü:
standard,expressveyaovernight - Ondalık sayı olarak paket ağırlığı (örneğin,
4.5)
Bir OrderProcessor oluşturun, girdi türüne göre uygun nakliye stratejisini ayarlayın, ardından siparişi işleyin ve hesaplanan maliyeti yazdırın.
Örneğin, girdiler express ve 4.5 ise, çıktı şöyle olmalıdır:
18.5Bu, Strateji deseninin gücünü gösterir - OrderProcessor sınıfınızın kendisi herhangi bir nakliye hesaplama mantığı içermez. Sadece kendisine verilen stratejiye yetki devreder (delegate), bu da işlemciyi hiç değiştirmeden yeni nakliye yöntemleri (örneğin DroneDelivery) eklemeyi kolaylaştırır!
Kopya kağıdı
Strateji deseni (Strategy pattern), bir algoritma ailesi tanımlayan, her birini kendi sınıfına kapsülleyen ve bunları çalışma zamanında birbirinin yerine kullanılabilir hale getiren davranışsal bir desendir.
Desen üç bölümden oluşur:
- Strateji arayüzü (Strategy interface): algoritma sözleşmesini tanımlar
- Somut strateji sınıfları (Concrete strategy classes): farklı davranışları uygular
- Bağlam sınıfı (Context class): uygulama detaylarını bilmeden bir stratejiyi kullanır
Örnek yapı:
// Strateji arayüzü
public interface IPaymentStrategy
{
void Pay(decimal amount);
}
// Somut stratejiler
public class CreditCardPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via Credit Card");
}
public class PayPalPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via PayPal");
}
// Bağlam sınıfı
public class ShoppingCart
{
private IPaymentStrategy _paymentStrategy;
public void SetPaymentMethod(IPaymentStrategy strategy)
{
_paymentStrategy = strategy;
}
public void Checkout(decimal total)
{
_paymentStrategy.Pay(total);
}
}Kullanım - çalışma zamanında stratejileri değiştirme:
var cart = new ShoppingCart();
cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m); // Paid 99.99 via Credit Card
cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m); // Paid 49.99 via PayPalFaydaları:
- Karmaşık koşullu mantığı ortadan kaldırır
- Gelişime açık, değişime kapalıdır
- Yeni stratejiler eklemek sadece yeni sınıflar oluşturmayı gerektirir, mevcut kodda değişiklik yapılmaz
Kendin dene
using System;
using Shipping;
class Program
{
public static void Main(string[] args)
{
// Girdiyi oku
string shippingType = Console.ReadLine();
double weight = Convert.ToDouble(Console.ReadLine());
// TODO: Bir OrderProcessor örneği oluşturun
// TODO: shippingType değerine göre ("standard", "express" veya "overnight"),
// uygun gönderim stratejisini oluşturun ve işlemci üzerinde ayarlayın
// TODO: Siparişi işleyin ve hesaplanan maliyeti yazdırın
}
}
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
1OOP Temelleri
Harici Dosyalarİsim Alanları ve YönergelerSınıf ve Nesnelere Giriş'this' Anahtar KelimesiMetotlar ve ParametrelerAlanlar ve ÖzelliklerYapıcı MetotlarNesne BaşlatıcılarÖzet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtım (:) Sözdizimi'base' Anahtar KelimesiVirtual ve Override Anahtar KelimeleriSealed Sınıflar'object' Temel SınıfıÖzet - Çalışan Hiyerarşisi7İleri Düzey Özellikler
Operatör Aşırı Yüklemeİndeksleyiciler (this[])ToString() Geçersiz KılmaGenişletme MetotlarıÖzet - Özel Liste10Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişThread-Safe SingletonFactory KalıbıObserver Kalıbı (Olaylar)Strategy Kalıbı2Özellikler ve Statik Üyeler
Otomatik Uygulanan ÖzelliklerSadece Okunur/Yazılır ÖzelliklerStatik Alanlar ve MetotlarStatik Sınıflarİfade Gövdeli Üyeler5Polimorfizm ve Arayüzler
Derleme vs Çalışma Zamanı PolimorfizmiArayüz vs Soyut SınıfÇoklu ArayüzlerBelirgin ArayüzlerUpcasting ve DowncastingÖzet - Şekil Hesaplayıcı8İleri Düzey OOP Kavramları
Kalıtım yerine KompozisyonGenerics (Sınıflar ve Metotlar)Delegates ve EventlerAttributes ve ReflectionIDisposable ve using İfadesiDependency Injection Temelleri11Tasarı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ı3Sınıf Mimarisi
Örnek vs Statik Veri'readonly' ve 'const' Anahtar KelimeleriDestekleyici Alanlar (Backing Fields)Özet - Banka Hesabı Yöneticisi6Kapsülleme
Erişim BelirleyicilerKapsülleme için ÖzelliklerVeri Gizleme UygulamasıDeğişmezlik KalıplarıÖzet - Öğrenci Kayıtları