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.

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ı işlemek 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 düşün. Para bekliyor, has ödeme almış ya da bir ürün dağıtıyor olmasına bağlı olarak farklı davranır.

Her durumun hangi eylemlere izin verildiğine ilişkin kendi kuralları vardır. 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";
    }
}

Bağlam 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, kapsamlı switch ifadelerini ortadan kaldırır ve yeni durumlar eklemeyi kolaylaştırır. Her durum sınıfı, kendisinden sonra hangi durumun geleceğini bilmekten sorumludur; bu sayede mantık düzenli ve sürdürülebilir kalır.

challenge icon

Görev

Kolay

State Pattern'ı kullanarak bir belge iş akışı sistemi oluşturalım. Bir içerik yönetim sistemindeki belgeler, taslak, inceleme ve yayımlanmış gibi farklı aşamalardan geçer; 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 dosyaya ayıracaksınız:

  • 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 ilerletmeyi denemek 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 bunu uygulayan üç durum sınıfı oluşturun:
    • DraftState: publish() çağrıldığında belgeyi ReviewState durumuna geçirir ve "Document sent for review" döndürür. Durumu "Draft" şeklindedir.
    • ReviewState: publish() çağrıldığında belgeyi PublishedState durumuna geçirir ve "Document published" döndürür. Durumu "Under Review" şeklindedir.
    • PublishedState: publish() çağrıldığında durumu değiştirmeden "Document is already published" döndürür. Durumu "Published" şeklindedir.
  • Document.php: States dosyasını dahil edin ve bağlam görevi gören bir Document sınıfı oluşturun. Belgeniz:
    • Yapıcısında bir başlık kabul etmeli ve DraftState durumunda başlamalıdır
    • Mevcut durumu değiştirmek için setState(DocumentState $state): void yöntemine sahip olmalıdır
    • Mevcut durumun publish(): string yöntemine delege eden bir publish() yöntemine sahip olmalıdır
    • Mevcut durumun durumunu 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ğı.

    Başlığı Document olan bir "My Article" oluşturun. Önce 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ırda yazdırın. Son olarak, son durumu yazdırın.

    Çıktı biçimi:

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

Her durum sınıfı, iş akışında hangi durumun sırada olduğunu bilir; böylece geçiş mantığı düzenli ve kolayca değiştirilebilir kalır. "Archived" gibi yeni bir durum eklemek, yalnızca yeni bir sınıf oluşturmak ve ilgili geçişleri güncellemek anlamına gelir.

Kendin dene

<?php

require_once 'Document.php';

// Girdiyi oku - publish() çağırma sayısı
$n = intval(trim(fgets(STDIN)));

// TODO: "My Article" başlıklı bir Document oluştur

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

// TODO: publish() metodunu n kez çağır, her sonucu yeni bir satıra yazdır

// TODO: Son durumu şu formatta yazdır: "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

Kendi başına pratik yap: Online PHP derleyicisi