Menu
Coddy logo textTech

Durum Kalıbı

Coddy'nin PHP Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 79 / 91.

Durum Deseni (State Pattern), bir nesnenin iç durumu değiştiğinde davranışını değiştirmesine olanak tanıyan davranışsal bir tasarım desenidir. Farklı durumları yönetmek için karmaşık koşullu ifadeler kullanmak yerine, her durumu kendi sınıfında kapsüller ve davranışı mevcut durum nesnesine devredersiniz.

Bir otomat makinesini düşünün. Para bekliyor olmasına, ödemeyi almış olmasına veya bir ürün veriyor olmasına bağlı olarak farklı davranır.

Her durumun, hangi eylemlere izin verildiğine dair kendi kuralları vardır. Durum Deseni (State Pattern), her durum için bir sınıf oluşturarak bunu modeller.

<?php
interface OrderState {
    public function proceed(Order $order): string;
    public function getStatus(): string;
}

class PendingState implements OrderState {
    public function proceed(Order $order): string {
        $order->setState(new ProcessingState());
        return "Order moved to processing";
    }
    
    public function getStatus(): string {
        return "Pending";
    }
}

class ProcessingState implements OrderState {
    public function proceed(Order $order): string {
        $order->setState(new ShippedState());
        return "Order has been shipped";
    }
    
    public function getStatus(): string {
        return "Processing";
    }
}

class ShippedState implements OrderState {
    public function proceed(Order $order): string {
        return "Order already shipped";
    }
    
    public function getStatus(): string {
        return "Shipped";
    }
}

Context sınıfı, mevcut duruma bir referans tutar ve çağrıları ona devreder:

<?php
class Order {
    private OrderState $state;
    
    public function __construct() {
        $this->state = new PendingState();
    }
    
    public function setState(OrderState $state): void {
        $this->state = $state;
    }
    
    public function proceed(): string {
        return $this->state->proceed($this);
    }
    
    public function getStatus(): string {
        return $this->state->getStatus();
    }
}

$order = new Order();
echo $order->getStatus() . "\n";
echo $order->proceed() . "\n";
echo $order->getStatus() . "\n";
echo $order->proceed() . "\n";
echo $order->getStatus();

Çıktı:

Pending
Order moved to processing
Processing
Order has been shipped
Shipped

State Pattern, karmaşık switch ifadelerini ortadan kaldırır ve yeni durumlar eklemeyi kolaylaştırır. Her durum sınıfı, bir sonraki durumun hangisi olduğunu bilmekten sorumludur; bu da mantığı düzenli ve sürdürülebilir tutar.

challenge icon

Görev

Kolay

State Pattern kullanarak bir belge iş akışı sistemi oluşturalım. Bir içerik yönetim sistemindeki belgeler farklı aşamalardan geçer — taslak, inceleme ve yayınlanmış — ve her aşamanın hangi eylemlere izin verildiği ve belgeyi ilerletmeye çalıştığınızda ne olacağı konusunda kendi kuralları vardır.

Kodunuzu dört dosya halinde düzenleyeceksiniz:

  • DocumentState.php — Tüm belge durumları için sözleşmeyi belirleyen bir DocumentState arayüzü tanımlayın. İki yöntemi olmalıdır: belgeyi ilerletmeye çalışmak için publish(Document $document): string ve mevcut durum adını döndürmek için getStatus(): string.
  • States.php — DocumentState arayüzünü dahil edin ve onu uygulayan üç durum sınıfı oluşturun:
    • DraftStatepublish() çağrıldığında, belgeyi ReviewState durumuna geçirir ve "Document sent for review" döndürür. Durumu "Draft" şeklindedir.
    • ReviewStatepublish() çağrıldığında, belgeyi PublishedState durumuna geçirir ve "Document published" döndürür. Durumu "Under Review" şeklindedir.
    • PublishedStatepublish() çağrıldığında, durum değiştirmeden "Document is already published" döndürür. Durumu "Published" şeklindedir.
  • Document.php — States dosyasını dahil edin ve bağlam (context) görevi gören bir Document sınıfı oluşturun. Belgeniz şunları yapmalıdır:
    • Yapıcısında (constructor) bir başlık kabul etmeli ve DraftState durumunda başlamalıdır
    • Mevcut durumu değiştirmek için bir setState(DocumentState $state): void yöntemine sahip olmalıdır
    • Mevcut durumun publish() yöntemine delege eden bir publish(): string yöntemine sahip olmalıdır
    • Mevcut durumun statüsünü döndüren bir getStatus(): string yöntemine sahip olmalıdır
  • main.php — Document dosyasını dahil edin. Bir girdi alacaksınız: belge üzerinde publish() yönteminin kaç kez çağrılacağı.

    "My Article" başlığıyla bir Document oluşturun. İlk olarak, başlangıç durumunu yazdırın. Ardından, publish() yöntemini belirtilen sayıda çağırın ve her çağrının sonucunu yeni bir satıra yazdırın. Son olarak, final durumunu yazdırın.

    Çıktı formatı:

    Status: [initial status]
    [publish result 1]
    [publish result 2]
    ...
    Status: [final status]

Her durum sınıfı, iş akışında bir sonraki durumun hangisi olduğunu bilir, bu da geçiş mantığını düzenli ve değiştirilmesi kolay tutar. "Archived" gibi yeni bir durum eklemek, sadece yeni bir sınıf oluşturmak ve ilgili geçişleri güncellemek anlamına gelecektir.

Kopya kağıdı

Durum Deseni (State Pattern), her bir durumu kendi sınıfında kapsülleyerek, bir nesnenin iç durumu değiştiğinde davranışını değiştirmesine olanak tanıyan davranışsal bir tasarım desenidir.

Tüm durum sınıflarının uygulayacağı bir durum arayüzü tanımlayın:

<?php
interface OrderState {
    public function proceed(Order $order): string;
    public function getStatus(): string;
}

Arayüzü uygulayan somut durum sınıfları oluşturun:

<?php
class PendingState implements OrderState {
    public function proceed(Order $order): string {
        $order->setState(new ProcessingState());
        return "Order moved to processing";
    }
    
    public function getStatus(): string {
        return "Pending";
    }
}

class ProcessingState implements OrderState {
    public function proceed(Order $order): string {
        $order->setState(new ShippedState());
        return "Order has been shipped";
    }
    
    public function getStatus(): string {
        return "Processing";
    }
}

class ShippedState implements OrderState {
    public function proceed(Order $order): string {
        return "Order already shipped";
    }
    
    public function getStatus(): string {
        return "Shipped";
    }
}

Mevcut duruma bir referans tutan ve çağrıları ona devreden bir bağlam (context) sınıfı oluşturun:

<?php
class Order {
    private OrderState $state;
    
    public function __construct() {
        $this->state = new PendingState();
    }
    
    public function setState(OrderState $state): void {
        $this->state = $state;
    }
    
    public function proceed(): string {
        return $this->state->proceed($this);
    }
    
    public function getStatus(): string {
        return $this->state->getStatus();
    }
}

Kullanım örneği:

$order = new Order();
echo $order->getStatus() . "\n";  // Pending
echo $order->proceed() . "\n";     // Order moved to processing
echo $order->getStatus() . "\n";   // Processing
echo $order->proceed() . "\n";     // Order has been shipped
echo $order->getStatus();          // Shipped

Durum Deseni, karmaşık switch ifadelerini ortadan kaldırır ve yeni durumlar eklemeyi kolaylaştırır. Her durum sınıfı, bir sonraki durumun hangisi olacağını bilmekten sorumludur.

Kendin dene

<?php

require_once 'Document.php';

// Girdiyi oku - publish() fonksiyonunun kaç kez çağrılacağı
$n = intval(trim(fgets(STDIN)));

// YAPILACAK: "My Article" başlıklı bir Document oluşturun

// YAPILACAK: Başlangıç durumunu şu formatta yazdırın: "Status: [status]"

// YAPILACAK: publish() fonksiyonunu n kez çağırın ve her sonucu yeni bir satıra yazdırın

// YAPILACAK: Son durumu şu formatta yazdırın: "Status: [status]"

?>
quiz iconKendini test et

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