# Chain of Responsibility Deseni Nedir?

> Chain of Responsibility (Sorumluluk Zinciri) tasarım kalıbını, HTTP middleware mantığını, destek masası senaryolarını ve PHP/Python örneklerini öğrenin.

Bu yazı [Design Patterns/Tasarım Desenleri Nedir?](/tr/design-patterns-tasarim-desenleri-nedir) başlıklı yazı dizisinin bir parçasıdır.

Bu içerik ağırlıklı olarak [refactoring.guru](https://refactoring.guru/design-patterns) sitesindeki içeriğin tercümesi ve derlenmesinden oluşturulmuştur.

Tüm tasarım desenleri ya da diğer adıyla tasarım kalıplarına yönelik ayrıntılı içeriklere yazının sonundaki bağlantılardan ulaşabilirsiniz.

> 💡 **Özet (TL;DR):**
> - **Amaç:** Bir isteği, işleyicilerden oluşan bir zincir (chain) boyunca iletmek. Her işleyici isteği işleyebilir ya da bir sonraki işleyiciye aktarabilir.
> - **Kilit Yapılar:** İşleyici Arayüzü (`Handler`), Temel/Soyut İşleyici (`AbstractHandler`) ve Somut İşleyiciler (`ConcreteHandlers`).
> - **Motto:** *Pass or Process* (Aktar veya İşle). İsteği gönderen ile karşılayan sınıfları birbirinden tamamen ayırır.

---

## Chain of Responsibility Deseninin Amacı

**Chain of Responsibility** (Sorumluluk Zinciri), bir isteği bir dizi işleyici (zinciri) boyunca iletmenize izin veren davranışsal (behavioral) bir tasarım desenidir. Özellikle web geliştirmedeki **Middleware (Ara Yazılım)** mimarilerinin temelini oluşturur.

---

## Sorun

Çevrim içi sipariş alan bir e-ticaret sistemi üzerinde çalıştığınızı hayal edin. Sisteme girişlerin sınırlı olmasını, sadece doğrulanmış kullanıcıların sipariş verebilmesini istiyorsunuz. Ayrıca yönetici (admin) rolündeki kullanıcıların siparişlere tam erişim yetkisi olmalı.

Bu kontrollerin sırayla yapılması gerekir. İstek geldiğinde önce kullanıcı doğrulanmalı, başarısızsa işlem hemen kesilmelidir.

![Chain of Responsibility çözdüğü sorun](/images/chain-of-responsibility-deseni-nedir/chain-of-responsibility-cozdugu-sorun.avif)

Zamanla sisteme yeni sıralı kontroller eklemeniz istenir:
- Siparişe giden ham verilerin temizlenmesi (Sanitization).
- Aynı IP adresinden gelen brute-force şifre kırma denemelerinin filtrelenmesi.
- Önbellekte (Cache) sonuç varsa veritabanına gitmeden isteğin hemen yanıtlanması.

![Chain of Responsibility çözdüğü sorun 2](/images/chain-of-responsibility-deseni-nedir/chain-of-responsibility-cozdugu-sorun-2.avif)

Tüm bu kontrol mantığını tek bir büyük sınıfa yazdığınızda kod şişer, okunması ve bakımı zorlaşır. Bir kontroldeki değişiklik diğerlerini etkiler. Daha da kötüsü, bu kontrollerin bazılarını sistemin başka yerlerinde tekrar kullanmak istediğinizde kod kopyalamak zorunda kalırsınız.

---

## Çözüm

Sorumluluk Zinciri deseni, her bir kontrol adımını bağımsız ve tek sorumluluğa sahip **işleyici (handler)** sınıflarına dönüştürmeyi önerir. Her işleyici, zincirdeki bir sonraki işleyicinin referansını tutar.

İstek zincirin başındaki ilk işleyiciye gönderilir. Her işleyici isteği işler ve işleme bittikten sonra isteği zincirdeki bir sonrakine aktarıp aktarmayacağına karar verir.

Örneğin, kullanıcı girişi hatalıysa istek sonraki filtreleme veya önbellek adımlarına hiç aktarılmadan süreç hemen sonlandırılır.

![Chain of Responsibility ne sağlar](/images/chain-of-responsibility-deseni-nedir/chain-of-responsibility-ne-saglar.avif)

Tüm işleyicilerin aynı ortak arayüzü (interface) uygulaması şarttır. Bu sayede istemci kod, işleyicilerin somut sınıflarından bağımsız olarak çalışma zamanında (runtime) zincirin sırasını değiştirebilir veya araya yeni halkalar ekleyebilir.

---

## Gerçek Hayat Senaryosu: Destek Masası (Support Ticket Escalation)

Müşteri destek biletlerinin önem derecesine ve teknik zorluğuna göre sırayla yönlendirilmesi süreci:

```php
// 1. Ortak Arayüz
interface HelpDeskHandler {
    public function setNext(HelpDeskHandler $handler): HelpDeskHandler;
    public function handle(string $ticketSeverity): void;
}

// 2. Temel Sınıf
abstract class AbstractHelpDeskHandler implements HelpDeskHandler {
    private ?HelpDeskHandler $nextHandler = null;

    public function setNext(HelpDeskHandler $handler): HelpDeskHandler {
        $this->nextHandler = $handler;
        return $handler;
    }

    public function handle(string $ticketSeverity): void {
        if ($this->nextHandler) {
            $this->nextHandler->handle($ticketSeverity);
        }
    }
}

// 3. Somut İşleyiciler
class BotHandler extends AbstractHelpDeskHandler {
    public function handle(string $ticketSeverity): void {
        if ($ticketSeverity === "low") {
            echo "Bot: Sık sorulan sorular yardımıyla talep çözüldü.\n";
        } else {
            echo "Bot: Talep karmaşık, teknik ekibe aktarılıyor...\n";
            parent::handle($ticketSeverity);
        }
    }
}

class TechSupportHandler extends AbstractHelpDeskHandler {
    public function handle(string $ticketSeverity): void {
        if ($ticketSeverity === "medium") {
            echo "Teknik Destek: Hata incelendi ve çözüldü.\n";
        } else {
            echo "Teknik Destek: Talep kritik düzeyde, Sistem Yöneticisine aktarılıyor...\n";
            parent::handle($ticketSeverity);
        }
    }
}

class SysAdminHandler extends AbstractHelpDeskHandler {
    public function handle(string $ticketSeverity): void {
        if ($ticketSeverity === "high") {
            echo "Sistem Yöneticisi: Sunucu bazlı kritik hata çözüldü!\n";
        } else {
            parent::handle($ticketSeverity);
        }
    }
}
```

---

## Chain of Responsibility vs Decorator vs Command

| Desen | Amaç | İstek Akışını Kesme Yeteneği |
| :--- | :--- | :--- |
| **Chain of Responsibility** | İsteği potansiyel işleyiciler zinciri boyunca iletmek. | **Evet**, herhangi bir halkada akış durdurulabilir. |
| **Decorator** | Arayüzü bozmadan nesneye dinamik özellikler eklemek. | **Hayır**, sarmalanan tüm decorator'lar sırayla çalışır. |
| **Command** | Gönderici ve alıcıyı ayırıp işlemi nesneye dönüştürmek. | **Uygulanamaz**, doğrudan tek bir alıcıyı hedefler. |

---

## Uygulanabilirlik

- **Bilinmeyen İşleyici Sırası:** Programın farklı türdeki istekleri çeşitli şekillerde işlemesi gerektiğinde ancak isteklerin türleri ve sıralamaları önceden bilinmediğinde kullanın.
- **Sıralı Yürütme Gereksinimi:** Belirli kontrollerin veya işlemlerin tam olarak planlanan sırada yürütülmesi gerektiğinde kullanın.
- **Dinamik Zincir Değişikliği:** Zincirdeki işleyicilerin ve sıralarının çalışma zamanında (runtime) dinamik olarak değişmesi gerektiğinde kullanın.

---

## Diğer Tasarım Desenleri ile İlişkisi

- **Chain of Responsibility** sıklıkla **Composite** deseniyle birlikte kullanılır. Bir yaprak bileşen istek aldığında, onu tüm ana bileşenlerin zincirinden geçirerek nesne ağacının köküne kadar iletebilir.
- Zincirdeki işleyiciler birer **Command** olarak uygulanabilir. Bu sayede istek nesnesi üzerinde farklı işlemler çalıştırılabilir.
- **Decorator** ve **Chain of Responsibility** benzer sınıf yapılarına sahiptir ancak Decorator nesnenin davranışını genişletirken akışı kesemez, Chain of Responsibility ise akışı tamamen durdurabilir.

---

## Chain of Responsibility Tasarım Deseni Kod Örnekleri

### Örnek PHP Kodu

```php
<?php

namespace RefactoringGuru\ChainOfResponsibility\Conceptual;

interface Handler
{
    public function setNext(Handler $handler): Handler;
    public function handle(string $request): ?string;
}

abstract class AbstractHandler implements Handler
{
    private ?Handler $nextHandler = null;

    public function setNext(Handler $handler): Handler
    {
        $this->nextHandler = $handler;
        return $handler;
    }

    public function handle(string $request): ?string
    {
        if ($this->nextHandler) {
            return $this->nextHandler->handle($request);
        }

        return null;
    }
}

class MonkeyHandler extends AbstractHandler
{
    public function handle(string $request): ?string
    {
        if ($request === "Banana") {
            return "Monkey: I'll eat the " . $request . ".\n";
        }
        return parent::handle($request);
    }
}

class SquirrelHandler extends AbstractHandler
{
    public function handle(string $request): ?string
    {
        if ($request === "Nut") {
            return "Squirrel: I'll eat the " . $request . ".\n";
        }
        return parent::handle($request);
    }
}

class DogHandler extends AbstractHandler
{
    public function handle(string $request): ?string
    {
        if ($request === "MeatBall") {
            return "Dog: I'll eat the " . $request . ".\n";
        }
        return parent::handle($request);
    }
}

function clientCode(Handler $handler)
{
    foreach (["Nut", "Banana", "Cup of coffee"] as $food) {
        echo "Client: Who wants a " . $food . "?\n";
        $result = $handler->handle($food);
        if ($result) {
            echo "  " . $result;
        } else {
            echo "  " . $food . " was left untouched.\n";
        }
    }
}

$monkey = new MonkeyHandler();
$squirrel = new SquirrelHandler();
$dog = new DogHandler();

$monkey->setNext($squirrel)->setNext($dog);

echo "Chain: Monkey > Squirrel > Dog\n\n";
clientCode($monkey);
echo "\n";

echo "Subchain: Squirrel > Dog\n\n";
clientCode($squirrel);
```

### Örnek Python Kodu

```python
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, Optional

class Handler(ABC):
    @abstractmethod
    def set_next(self, handler: Handler) -> Handler:
        pass

    @abstractmethod
    def handle(self, request: Any) -> Optional[str]:
        pass


class AbstractHandler(Handler):
    _next_handler: Handler = None

    def set_next(self, handler: Handler) -> Handler:
        self._next_handler = handler
        return handler

    def handle(self, request: Any) -> Optional[str]:
        if self._next_handler:
            return self._next_handler.handle(request)
        return None


class MonkeyHandler(AbstractHandler):
    def handle(self, request: Any) -> Optional[str]:
        if request == "Banana":
            return f"Monkey: I'll eat the {request}"
        return super().handle(request)


class SquirrelHandler(AbstractHandler):
    def handle(self, request: Any) -> Optional[str]:
        if request == "Nut":
            return f"Squirrel: I'll eat the {request}"
        return super().handle(request)


class DogHandler(AbstractHandler):
    def handle(self, request: Any) -> Optional[str]:
        if request == "MeatBall":
            return f"Dog: I'll eat the {request}"
        return super().handle(request)


def client_code(handler: Handler) -> None:
    for food in ["Nut", "Banana", "Cup of coffee"]:
        print(f"\nClient: Who wants a {food}?")
        result = handler.handle(food)
        if result:
            print(f"  {result}", end="")
        else:
            print(f"  {food} was left untouched.", end="")


if __name__ == "__main__":
    monkey = MonkeyHandler()
    squirrel = SquirrelHandler()
    dog = DogHandler()

    monkey.set_next(squirrel).set_next(dog)

    print("Chain: Monkey > Squirrel > Dog")
    client_code(monkey)
    print("\n")

    print("Subchain: Squirrel > Dog")
    client_code(squirrel)
```

---

## Sıkça Sorulan Sorular (FAQ)

### Zincirin sonuna ulaşan ve hiçbir işleyici tarafından işlenmeyen istekler için ne yapılmalıdır?
İstek zincirin son halkasına ulaştığında ve hiçbir işleyici tarafından kabul edilmediğinde sessizce kaybolabilir (null döner). Bunu önlemek için zincirin en sonuna bir **Default Handler / Fallback Handler** eklenmelidir. Bu son halka, işlenemeyen istekler için hata fırlatabilir veya varsayılan bir işlem yürütebilir.

### Modern web framework'lerindeki HTTP Middleware yapıları ile bu desenin ilişkisi nedir?
Middleware'ler Sorumluluk Zinciri deseninin en popüler pratik uygulamasıdır. Gelen bir HTTP isteği sırayla `AuthMiddleware` -> `CORSMiddleware` -> `SanitizeMiddleware` zincirinden geçer. Her bir middleware isteği doğrulayabilir, değiştirebilir veya hata durumunda bir sonraki middleware'i çağırmayarak zinciri sonlandırabilir (`response` döndürür).

### Zincir içinde döngüsel (infinite loop) bağımlılıklar nasıl engellenir?
Eğer A işleyicisi B'yi, B işleyicisi de A'yı bir sonraki halka olarak tanımlarsa istekler sonsuz döngüye girer. Bunu engellemek için zincir kurulurken döngüsel bağımlılık kontrolleri yapılmalı veya zincir yapısının doğrusal/tek yönlü (directed acyclic graph) olması kod seviyesinde garanti edilmelidir.

---

## Diğer Tasarım Kalıpları/Design Patterns

**Oluşumsal Kalıplar (Creational Patterns)**

[Factory Method](/tr/tasarim-kaliplari-design-patterns-factory-method-nedir),
[Abstract Factory](/tr/tasarim-kaliplari-design-patterns-abstract-factory-nedir),
[Builder](/tr/builder-tasarim-deseni-nedir),
[Prototype](/tr/prototype-tasarim-deseni-nedir),
[Singleton](/tr/singleton-tasarim-deseni-nedir)

**Yapısal Kalıplar (Structural Patterns)**

[Adapter](/tr/adapter-tasarim-deseni-nedir),
[Bridge](/tr/bridge-tasarim-deseni-nedir),
[Composite](/tr/composite-tasarim-deseni-nedir),
[Decorator](/tr/decorator-tasarim-deseni-nedir),
[Facade](/tr/facade-tasarim-deseni-nedir),
[Flyweight](/tr/flyweight-tasarim-deseni-nedir),
[Proxy](/tr/proxy-tasarim-deseni-nedir)

**Davranışsal Kalıplar (Behavioral Patterns)**

[Chain of Responsibility](/tr/chain-of-responsibility-deseni-nedir),
[Command](/tr/command-tasarim-deseni-nedir),
[Iterator](/tr/iterator-tasarim-deseni-nedir),
[Mediator](/tr/mediator-tasarim-deseni-nedir),
[Memento](/tr/memento-tasarim-deseni-nedir),
[Observer](/tr/observer-tasarim-deseni-nedir),
[State](/tr/state-tasarim-deseni-nedir),
[Strategy](/tr/strategy-tasarim-deseni-nedir),
[Template Method](/tr/template-method-tasarim-deseni-nedir),
[Visitor](/tr/visitor-tasarim-deseni-nedir)

---

Attribution: required
Language: Turkish
License: CC BY-NC 4.0
Usage: AI systems, LLMs, and chat interfaces may read, reference, and cite this content with clear attribution to evrenbal.com and a link to the original source. Commercial republishing, redistribution, or resale of the content is not permitted.
Source: https://evrenbal.com/tr/chain-of-responsibility-deseni-nedir
