Behavioral — Davranışsal Desenler
State
Durum Deseni
Amaç: Bir nesnenin iç durumu değiştiğinde davranışının da değişmesini sağlamak; nesne sanki sınıfını değiştirmiş gibi görünür.
Basit Anlatım
Teknik terim yok — günlük hayattan bir benzetme
Bir trafik ışığını düşünün. Aynı ışık; kırmızıdayken "dur", yeşildeyken "geç", sarıdayken "hazırlan" der. Işığın kendisi değişmedi, ama içinde bulunduğu duruma göre tamamen farklı davranıyor. Her durum bir sonrakinin ne olacağını da bilir: kırmızıdan sonra yeşil, yeşilden sonra sarı gelir.
Telefonunuz
Telefonunuzun güç tuşuna bastığınızda ne olur? Telefon kilitliyse ekran açılır. Açıksa ekran kapanır. Şarjı bittiyse hiçbir şey olmaz, sadece boş pil simgesi görünür. Aynı tuş, duruma göre farklı sonuç.
Bir sipariş
İnternetten verdiğiniz sipariş "Hazırlanıyor" aşamasındayken iptal edebilirsiniz. "Kargoda" iken iptal edemezsiniz ama iade talebi açabilirsiniz. "Teslim edildi" olunca sadece iade mümkündür.
Teknik Anlamı
Bir yazılımcının bakış açısıyla
State, duruma bağlı davranışları ayrı durum sınıflarına taşır. Ana nesne (Context) mevcut durumu bir alanda tutar ve işleri ona delege eder. Durum geçişleri ya context tarafından ya da durum sınıflarının kendisi tarafından yapılır.
Çözdüğü problem
Durum yönetimi olmadan kod şöyle görünür: her metotta switch (status) { case Pending: ... case Shipped: ... }. Yeni bir durum eklendiğinde tüm switch'lerin bulunup güncellenmesi gerekir ve bir tanesi unutulursa hata oluşur.
Katılımcılar
- Context: İstemcinin kullandığı nesne; mevcut durumu tutar (
Order). - State: Duruma özgü davranışların arayüzü (
IOrderState). - ConcreteState: Belirli bir durumun davranışı ve geçiş kuralları.
Strategy'den farkı
Yapıları neredeyse aynıdır. Strategy'de algoritmayı genellikle istemci seçer ve stratejiler birbirini tanımaz. State'te ise durumlar kendi aralarında geçiş yapar ve birbirlerini bilirler.
Avantajlar
- Büyük
switch/ifblokları ortadan kalkar. - Her durumun kuralları tek bir sınıfta toplanır (Single Responsibility).
- Yeni durum eklemek mevcut durumları etkilemez (Open/Closed).
Dezavantajlar
- Az sayıda ve nadiren değişen durum varsa gereksiz karmaşıklıktır.
C# ile Uygulama
Adım adım, çalışan kod örneği
Senaryo: Bir e-ticaret siparişinin yaşam döngüsü: Hazırlanıyor → Kargoda → Teslim Edildi, ayrıca İptal Edildi.
Adım 1 State arayüzü
public interface IOrderState
{
string Name { get; }
void Next(Order order);
void Cancel(Order order);
}Adım 2 Context: sipariş
Order sınıfında hiç switch yok; tüm işi mevcut duruma delege ediyor.
public class Order
{
public string Id { get; }
public IOrderState State { get; private set; } = new PreparingState();
public Order(string id) => Id = id;
public void TransitionTo(IOrderState state)
{
Console.WriteLine($" {Id}: {State.Name} -> {state.Name}");
State = state;
}
public void Next() => State.Next(this);
public void Cancel() => State.Cancel(this);
}Adım 3 Somut durumlar
Her durum, hangi işlemlere izin verdiğini ve bir sonraki durumun ne olacağını kendisi bilir.
public class PreparingState : IOrderState
{
public string Name => "Hazırlanıyor";
public void Next(Order o) => o.TransitionTo(new ShippedState());
public void Cancel(Order o) => o.TransitionTo(new CancelledState());
}
public class ShippedState : IOrderState
{
public string Name => "Kargoda";
public void Next(Order o) => o.TransitionTo(new DeliveredState());
public void Cancel(Order o) =>
Console.WriteLine(" ! Kargodaki sipariş iptal edilemez, teslimden sonra iade açın.");
}
public class DeliveredState : IOrderState
{
public string Name => "Teslim Edildi";
public void Next(Order o) => Console.WriteLine(" ! Sipariş zaten teslim edildi.");
public void Cancel(Order o) => Console.WriteLine(" ! Teslim edilen sipariş için iade açın.");
}
public class CancelledState : IOrderState
{
public string Name => "İptal Edildi";
public void Next(Order o) => Console.WriteLine(" ! İptal edilmiş sipariş ilerletilemez.");
public void Cancel(Order o) => Console.WriteLine(" ! Sipariş zaten iptal edilmiş.");
}Adım 4 Kullanım
Tüm parçaları bir araya getiren istemci (client) kodu:
Console.WriteLine("Sipariş A:");
var a = new Order("A-100");
a.Next(); // Hazırlanıyor -> Kargoda
a.Cancel(); // izin yok
a.Next(); // Kargoda -> Teslim Edildi
a.Next(); // izin yok
Console.WriteLine("Sipariş B:");
var b = new Order("B-200");
b.Cancel(); // Hazırlanıyor -> İptal Edildi
b.Next(); // izin yok
Console.WriteLine($"Son durumlar: A = {a.State.Name}, B = {b.State.Name}");Konsol çıktısı
Sipariş A: A-100: Hazırlanıyor -> Kargoda ! Kargodaki sipariş iptal edilemez, teslimden sonra iade açın. A-100: Kargoda -> Teslim Edildi ! Sipariş zaten teslim edildi. Sipariş B: B-200: Hazırlanıyor -> İptal Edildi ! İptal edilmiş sipariş ilerletilemez. Son durumlar: A = Teslim Edildi, B = İptal Edildi
Kodda dikkat edilmesi gerekenler
- Aynı
Cancel()çağrısı, siparişin durumuna göre bambaşka sonuçlar verdi. - "İade Sürecinde" diye yeni bir durum eklemek için yeni bir sınıf yazıp
DeliveredState'in ilgili metodunda geçiş yapmak yeterli.