Behavioral — Davranışsal Desenler

Chain of Responsibility

Sorumluluk Zinciri Deseni

Amaç: Bir isteği, onu işleyebilecek nesne bulunana kadar bir zincir boyunca iletmek; isteği gönderen ile işleyeni birbirinden ayırmak.

1

Basit Anlatım

Teknik terim yok — günlük hayattan bir benzetme

Bir şirkette harcama onayı istiyorsunuz. Kural şöyle: 1.000 TL'ye kadar olan harcamaları takım lideri, 10.000 TL'ye kadar müdür, 100.000 TL'ye kadar direktör onaylar. Daha fazlası için genel müdür gerekir.

Siz talebinizi her zaman takım liderine verirsiniz. Takım lideri yetkisi yetiyorsa onaylar; yetmiyorsa talebi müdüre iletir. Müdür de aynısını yapar. Talep, onu karşılayabilecek kişiye ulaşana kadar yukarı doğru ilerler.

Siz kimin onaylayacağını bilmek zorunda değilsiniz; sadece zincirin ilk halkasına verirsiniz.

Müşteri hizmetleri

Bir çağrı merkezini aradığınızda önce sesli yanıt sistemi karşılar. Çözemezse birinci seviye destek, o da çözemezse uzman ekip devreye girer.

Chain of Responsibility şunu der: "Elinden geliyorsa sen hallet, gelmiyorsa bir sonrakine ilet."
2

Teknik Anlamı

Bir yazılımcının bakış açısıyla

Chain of Responsibility, isteği işleyebilecek nesneleri (handler) bir zincir halinde bağlar. Her handler isteği ya işler ya da zincirdeki bir sonraki handler'a iletir. Bazı varyasyonlarda her handler işini yapıp yine de isteği iletir (pipeline).

Katılımcılar

.NET'ten tanıdık örnekler

Avantajlar

Dezavantajlar

3

C# ile Uygulama

Adım adım, çalışan kod örneği

Senaryo: Yukarıda anlatılan harcama onay süreci.

Adım 1 İstek modeli ve soyut Handler

SetNext handler'ı döndürdüğü için zincir akıcı biçimde kurulabilir.

public record ExpenseRequest(string Employee, decimal Amount, string Purpose);

public abstract class Approver
{
    private Approver? _next;

    public Approver SetNext(Approver next)
    {
        _next = next;
        return next;
    }

    public void Handle(ExpenseRequest request)
    {
        if (CanApprove(request.Amount))
            Console.WriteLine($"  {GetType().Name,-14} ONAYLADI: " +
                              $"{request.Purpose} ({request.Amount:N0} TL)");
        else if (_next is not null)
        {
            Console.WriteLine($"  {GetType().Name,-14} yetkisi yetmiyor, iletiliyor...");
            _next.Handle(request);
        }
        else
            Console.WriteLine($"  REDDEDİLDİ: {request.Amount:N0} TL kimsenin yetkisinde değil.");
    }

    protected abstract bool CanApprove(decimal amount);
}

Adım 2 Somut Handler'lar

Her biri yalnızca kendi yetki sınırını bilir.

public class TeamLead : Approver
{
    protected override bool CanApprove(decimal amount) => amount <= 1_000;
}

public class Manager : Approver
{
    protected override bool CanApprove(decimal amount) => amount <= 10_000;
}

public class Director : Approver
{
    protected override bool CanApprove(decimal amount) => amount <= 100_000;
}

public class CEO : Approver
{
    protected override bool CanApprove(decimal amount) => amount <= 1_000_000;
}

Adım 3 Kullanım

Tüm parçaları bir araya getiren istemci (client) kodu:

// Zinciri kur: TeamLead -> Manager -> Director -> CEO
var chain = new TeamLead();
chain.SetNext(new Manager()).SetNext(new Director()).SetNext(new CEO());

var requests = new[]
{
    new ExpenseRequest("Ayşe", 450, "Ofis malzemesi"),
    new ExpenseRequest("Can", 7_500, "Eğitim semineri"),
    new ExpenseRequest("Elif", 250_000, "Yeni sunucular"),
    new ExpenseRequest("Mert", 5_000_000, "Yeni bina"),
};

foreach (var r in requests)
{
    Console.WriteLine($"{r.Employee} -> {r.Amount:N0} TL talep etti:");
    chain.Handle(r);
}

Konsol çıktısı

Ayşe -> 450 TL talep etti:
  TeamLead       ONAYLADI: Ofis malzemesi (450 TL)
Can -> 7.500 TL talep etti:
  TeamLead       yetkisi yetmiyor, iletiliyor...
  Manager        ONAYLADI: Eğitim semineri (7.500 TL)
Elif -> 250.000 TL talep etti:
  TeamLead       yetkisi yetmiyor, iletiliyor...
  Manager        yetkisi yetmiyor, iletiliyor...
  Director       yetkisi yetmiyor, iletiliyor...
  CEO            ONAYLADI: Yeni sunucular (250.000 TL)
Mert -> 5.000.000 TL talep etti:
  TeamLead       yetkisi yetmiyor, iletiliyor...
  Manager        yetkisi yetmiyor, iletiliyor...
  Director       yetkisi yetmiyor, iletiliyor...
  REDDEDİLDİ: 5.000.000 TL kimsenin yetkisinde değil.

Kodda dikkat edilmesi gerekenler

Özetle: Chain of Responsibility, isteği işleyebilecek biri bulunana kadar bir zincir boyunca iletir; gönderen ile işleyeni birbirinden bağımsız kılar.
← Ana sayfaya dön