# State Tasarım Deseni Nedir?

> Bu yazı Design Patterns/Tasarım Desenleri nedir? başlıklı yazı dizisinin bir parçasıdır.

> 💡 **Özet (TL;DR):**
> - **Amacı:** Bir nesnenin iç durumu (state) değiştiğinde davranışını da dinamik olarak değiştirmesini sağlayan davranışsal (behavioral) bir tasarım desenidir.
> - **Çözdüğü Sorun:** Çok sayıda duruma ve karmaşık geçiş mantığına sahip olan sınıflardaki devasa `if-else` veya `switch-case` bloklarını ortadan kaldırır.
> - **Yöntem:** Her durumu ayrı bir sınıf olarak modeller ve bağlam (Context) nesnesinin davranışını aktif olan durum sınıfına delege eder.

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.

---

## State Tasarım Deseninin Amacı

**State**, bir nesnenin iç durumu değiştiğinde davranışını da değiştirmesini sağlayan davranışsal bir tasarım desenidir. Bu desen uygulandığında nesne, sanki çalışma zamanında kendi sınıfını (class) değiştirmiş gibi görünür.

---

## Sorun

State deseni [sonlu durum makineleri](https://tr.wikipedia.org/wiki/Sonlu_durum_makinesi) (finite state machines) konsepti ile yakından ilişkilidir.

![](/images/state-tasarim-deseni-nedir/sonlu-durum-makinesi.avif)

*Sonlu Durum Makinesi*

Ana fikir şudur: Herhangi bir zamanda, bir programın olabileceği sınırlı sayıda durum vardır. Herhangi bir benzersiz durumda program farklı şekilde hareket eder ve program durumu birinden diğerine anlık olarak geçiş yapabilir. Ancak mevcut duruma bağlı olarak, sistem bir başka duruma geçebilir veya geçemez. Bu geçiş kuralları (transitions) önceden belirlidir ve sonlu sayıdadır.

Bu yaklaşımı nesnelere de uygulayabilirsiniz. Bir `Document` sınıfınız olduğunu düşünün. Bir doküman şu 3 durumdan birinde olabilir: `Draft` (Taslak), `Moderation` (Moderasyonda) ve `Published` (Yayımlanmış). Dokümanın `publish` (yayınla) metodu her durumda farklı çalışır:

- **Taslak** durumundayken yayınlanırsa, moderasyon durumuna geçer.
- **Moderasyon** durumundayken dokümanı herkese açık hale getirir; ancak bunu sadece isteği gönderen kullanıcı bir yöneticiyse yapabilir.
- **Yayımlanmış** bir doküman için durumda herhangi bir değişiklik olmaz.

![](/images/state-tasarim-deseni-nedir/state-tasarim-deseni-nedir.avif)

*Bir doküman nesnesi için mümkün olan durumlar ve geçişler*

Durum makineleri (state machines) genel olarak, mevcut duruma göre uygun davranışı seçen koşullu ifadelerle (`if` veya `switch` gibi) uygulanır. Genelde bu durum, nesnenin bazı değişkenlerinin değerlerinden oluşur. Sonlu durum makinelerini daha önce duymadıysanız bile muhtemelen en az bir defa koşullu ifadelere dayalı bir durum yapısı kurmuşsunuzdur.

Koşullu ifadelere dayalı bir durum makinesinin en zayıf noktası, sisteme yeni durumlar ve duruma bağlı davranışlar eklemek istediğinizde ortaya çıkar. Çoğu metot, mevcut duruma göre doğru davranışı seçen devasa koşul ifadeleri içerecektir. Geçiş mantığında yapılacak en ufak bir değişiklik, tüm metotlardaki koşullu ifadelerin güncellenmesini gerektireceğinden bu tarz kodları yönetmek ve test etmek oldukça zordur.

Proje geliştikçe sorun daha da büyür. Bütün olası durumları ve geçişleri tasarım aşamasında planlamak hiç kolay değildir. Böyle olunca da başlangıçta çok yalın gözüken bir durum makinesi kodu, zamanla şişerek karmaşık ve spagetti bir yapıya dönüşebilir.

---

## Çözüm

State deseni, bir nesnenin tüm olası durumları için ayrı birer sınıf oluşturmanızı ve bu duruma özel davranışların hepsini bu sınıfların içerisine aktarmanızı önerir.

Bağlam (Context) adı verilen orijinal nesne, tüm davranışları kendisi uygulamak yerine, aktif durumu temsil eden durum nesnesinin referansını saklar ve durumla alakalı tüm işleri o nesneye delege eder.

![](/images/state-tasarim-deseni-nedir/state-deseni-ornegi.avif)

*Doküman nesnesinin işi durum nesnesine delege etmesi*

Bağlamın bir başka duruma geçiş yapması için, aktif durum nesnesi yeni durumu temsil eden başka bir nesne ile değiştirilir. Bunun mümkün olması için tüm durum sınıflarının aynı arayüzü (interface) esas alması şarttır. Böylece bağlam nesnesi, durum nesneleri ile bu ortak arayüz üzerinden iletişim kurabilir.

Bu yapı **Strategy** desenine benzer görünebilir; ancak aralarında çok temel bir fark vardır: State deseninde durum nesneleri birbirlerinden haberdar olabilir ve bir durumdan diğerine geçişi (transition) kendileri tetikleyebilir.

### State ve Strategy Desenleri Arasındaki Fark

| Özellik | State Deseni | Strategy Deseni |
| :--- | :--- | :--- |
| **Temel Amaç** | Nesnenin durumuna göre davranışını çalışma zamanında değiştirmek. | Bir işi yapmanın farklı yöntemlerini veya algoritmalarını sunmak. |
| **Geçiş Yönetimi** | Durum sınıfları sonraki durumu tetikleyebilir ve bağlamın durumunu değiştirebilir. | Algoritmalar birbirinden bağımsızdır; bağlama dışarıdan enjekte edilir. |
| **İletişim** | Durum nesneleri arasında geçiş ilişkisi (flow) vardır. | Strateji nesneleri birbirinden tamamen bihaberdir. |

---

## Uygulanabilirlik

**Mevcut durumuna bağlı olarak farklı hareket etmesi gereken nesneleriniz varsa, olası durum sayıları çok fazlaysa ve bu durumlara özel kodlar sık değişiyorsa State desenini kullanabilirsiniz.**

Bu desen, duruma özel tüm kodları ayrı sınıflara almanızı önerir. Böylece, diğerlerinden bağımsız olarak yeni durumlar ekleyebilir veya mevcut durumları değiştirebilirsiniz. Bu da kodun bakım maliyetini önemli ölçüde düşürür.

**Sınıfın belirli alanlarının değerlerine göre hareketlerini değiştirmek için kullanılan, aşırı miktarda koşullu ifadelere (`if-else` / `switch`) sahip kirli sınıfları temizlemek için bu deseni kullanabilirsiniz.**

State deseni, bu koşullu ifadeleri ilgili durum sınıflarına dönüştürmenizi sağlar. Bunu yaparken ana sınıfınızda durum yönetimi için kullandığınız geçici alanları ve yardımcı metotları temizleyebilirsiniz.

**Koşullu ifadeler esaslı bir durum makinesinde, benzer durumlar ve geçişler için tekrarlanan çok fazla kodunuz varsa bu deseni kullanabilirsiniz.**

State deseni, durum sınıfları için bir hiyerarşi oluşturmanızı ve ortak kodları temel bir soyut sınıf (abstract class) içine alarak kod tekrarlarını azaltmanızı sağlar.

---

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

- **Bridge**, **State**, **Strategy** (ve bir dereceye kadar **Adapter**) çok benzer yapılara sahiptir. Aslında bu desenlerin hepsi kompozisyon (composition), yani işi başka nesnelere delege etme esasına dayanır. Fakat her biri farklı bir soruna çözüm üretir.
- **State**, **Strategy** deseninin bir uzantısı olarak düşünülebilir. Her iki desen de kompozisyon esaslıdır: İkisi de işin bir bölümünü yardımcı nesnelere delege ederek bağlamın davranışını değiştirir. *Strategy*, nesneleri birbirinden tamamen bağımsız ve bihaber hale getirir. Öte yandan *State*, durumlar arasında bağımlılık olmasını sınırlamaz ve istedikleri zaman bağlam nesnesinin durumunu değiştirmelerine olanak tanır.

---

## State Deseni Kod Örnekleri

### Örnek PHP Kodu

```php
<?php

namespace RefactoringGuru\State\Conceptual;

/**
 * The Context defines the interface of interest to clients. It also maintains a
 * reference to an instance of a State subclass, which represents the current
 * state of the Context.
 */
class Context
{
    /**
     * @var State A reference to the current state of the Context.
     */
    private $state;

    public function __construct(State $state)
    {
        $this->transitionTo($state);
    }

    /**
     * The Context allows changing the State object at runtime.
     */
    public function transitionTo(State $state): void
    {
        echo "Context: Transition to " . get_class($state) . ".\n";
        $this->state = $state;
        $this->state->setContext($this);
    }

    /**
     * The Context delegates part of its behavior to the current State object.
     */
    public function request1(): void
    {
        $this->state->handle1();
    }

    public function request2(): void
    {
        $this->state->handle2();
    }
}

/**
 * The base State class declares methods that all Concrete State should
 * implement and also provides a backreference to the Context object, associated
 * with the State. This backreference can be used by States to transition the
 * Context to another State.
 */
abstract class State
{
    /**
     * @var Context
     */
    protected $context;

    public function setContext(Context $context)
    {
        $this->context = $context;
    }

    abstract public function handle1(): void;

    abstract public function handle2(): void;
}

/**
 * Concrete States implement various behaviors, associated with a state of the
 * Context.
 */
class ConcreteStateA extends State
{
    public function handle1(): void
    {
        echo "ConcreteStateA handles request1.\n";
        echo "ConcreteStateA wants to change the state of the context.\n";
        $this->context->transitionTo(new ConcreteStateB());
    }

    public function handle2(): void
    {
        echo "ConcreteStateA handles request2.\n";
    }
}

class ConcreteStateB extends State
{
    public function handle1(): void
    {
        echo "ConcreteStateB handles request1.\n";
    }

    public function handle2(): void
    {
        echo "ConcreteStateB handles request2.\n";
        echo "ConcreteStateB wants to change the state of the context.\n";
        $this->context->transitionTo(new ConcreteStateA());
    }
}

/**
 * The client code.
 */
$context = new Context(new ConcreteStateA());
$context->request1();
$context->request2();
```

### Örnek Python Kodu

```python
from __future__ import annotations
from abc import ABC, abstractmethod

class Context:
    """
    The Context defines the interface of interest to clients. It also maintains
    a reference to an instance of a State subclass, which represents the current
    state of the Context.
    """

    _state = None
    """
    A reference to the current state of the Context.
    """

    def __init__(self, state: State) -> None:
        self.transition_to(state)

    def transition_to(self, state: State):
        """
        The Context allows changing the State object at runtime.
        """

        print(f"Context: Transition to {type(state).__name__}")
        self._state = state
        self._state.context = self

    """
    The Context delegates part of its behavior to the current State object.
    """

    def request1(self):
        self._state.handle1()

    def request2(self):
        self._state.handle2()

class State(ABC):
    """
    The base State class declares methods that all Concrete State should
    implement and also provides a backreference to the Context object,
    associated with the State. This backreference can be used by States to
    transition the Context to another State.
    """

    @property
    def context(self) -> Context:
        return self._context

    @context.setter
    def context(self, context: Context) -> None:
        self._context = context

    @abstractmethod
    def handle1(self) -> None:
        pass

    @abstractmethod
    def handle2(self) -> None:
        pass

"""
Concrete States implement various behaviors, associated with a state of the
Context.
"""

class ConcreteStateA(State):
    def handle1(self) -> None:
        print("ConcreteStateA handles request1.")
        print("ConcreteStateA wants to change the state of the context.")
        self.context.transition_to(ConcreteStateB())

    def handle2(self) -> None:
        print("ConcreteStateA handles request2.")

class ConcreteStateB(State):
    def handle1(self) -> None:
        print("ConcreteStateB handles request1.")

    def handle2(self) -> None:
        print("ConcreteStateB handles request2.")
        print("ConcreteStateB wants to change the state of the context.")
        self.context.transition_to(ConcreteStateA())

if __name__ == "__main__":
    # The client code.

    context = Context(ConcreteStateA())
    context.request1()
    context.request2()
```

---

## 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/state-tasarim-deseni-nedir
