Dekoratör Kalıbı
Coddy'nin PHP Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 77 / 91.
Decorator Deseni (Dekoratör Deseni), nesneleri dekoratör adı verilen özel sarmalayıcı nesnelerin içine sararak onlara dinamik olarak yeni davranışlar eklemenize olanak tanıyan yapısal bir tasarım desenidir. Derleme zamanında davranış ekleyen kalıtımın aksine, dekoratörler çalışma zamanında davranış ekler.
Bir kahve dükkanı hayal edin. Temel bir kahve ile başlarsınız, ardından süt, şeker veya krem şanti gibi ekstralar eklersiniz.
Her ekleme orijinal kahveyi sarmalar ve onun açıklamasına ve maliyetine ekleme yapar. Temel nokta, hem temel kahvenin hem de dekoratörlerin aynı arayüzü paylaşmasıdır.
<?php
interface Coffee {
public function getDescription(): string;
public function getCost(): float;
}
class SimpleCoffee implements Coffee {
public function getDescription(): string {
return "Simple Coffee";
}
public function getCost(): float {
return 2.00;
}
}
Dekoratörler aynı arayüzü uygular ve başka bir Coffee nesnesini sarmalar:
<?php
class MilkDecorator implements Coffee {
public function __construct(private Coffee $coffee) {}
public function getDescription(): string {
return $this->coffee->getDescription() . ", Milk";
}
public function getCost(): float {
return $this->coffee->getCost() + 0.50;
}
}
class SugarDecorator implements Coffee {
public function __construct(private Coffee $coffee) {}
public function getDescription(): string {
return $this->coffee->getDescription() . ", Sugar";
}
public function getCost(): float {
return $this->coffee->getCost() + 0.25;
}
}
$coffee = new SimpleCoffee();
$coffee = new MilkDecorator($coffee);
$coffee = new SugarDecorator($coffee);
echo $coffee->getDescription() . " = $" . $coffee->getCost();
Çıktı:
Simple Coffee, Milk, Sugar = $2.75Her dekoratör, bir zincir oluşturacak şekilde önceki nesneyi sarmalar. Bu desen, her olası kombinasyon için bir sınıf oluşturmadan, davranışları herhangi bir sırada ve miktarda birleştirmenize olanak tanır. Çift süt mü lazım? Sadece iki kez sarmalayın.
Görev
KolayDecorator Desenini kullanarak bir pizza sipariş sistemi oluşturalım. Temel bir pizza ile başlayacak ve dinamik olarak malzemeler ekleyeceksiniz — her malzeme pizzayı sarmalar ve dersteki kahve örneğinde olduğu gibi açıklamasına ve fiyatına ekleme yapar.
Kodunuzu dört dosya halinde düzenleyeceksiniz:
Pizza.php— Tüm pizzalar ve malzemeler için sözleşmeyi belirleyen birPizzaarayüzü (interface) tanımlayın. İki yöntemi olmalıdır:getDescription(): stringvegetPrice(): float.BasePizza.php— Pizza arayüzünü dahil edin ve onu uygulayan (implement) birMargheritaPizzasınıfı oluşturun. Bu,"Margherita"açıklamasına ve8.00fiyatına sahip temel pizzanızdır.Toppings.php— Pizza arayüzünü dahil edin ve onu uygulayan üç dekoratör sınıfı oluşturun. Her dekoratör birPizzanesnesini sarmalar (bunu yapıcıda/constructor kabul edin) ve hem açıklamayı hem de fiyatı geliştirir:CheeseTopping— Açıklamaya", Extra Cheese"ve fiyata1.50eklerPepperoniTopping— Açıklamaya", Pepperoni"ve fiyata2.00eklerMushroomTopping— Açıklamaya", Mushrooms"ve fiyata1.25ekler
main.php— BasePizza ve Toppings dosyalarını dahil edin. Bir girdi alacaksınız: eklenecek malzemelerin virgülle ayrılmış bir listesi (örneğin,"cheese,pepperoni"veya"mushroom,cheese,cheese").Bir
MargheritaPizzaile başlayın. Girdideki her malzeme için pizzanızı uygun dekoratörle sarmalayın:"cheese",CheeseToppingile sarmalar"pepperoni",PepperoniToppingile sarmalar"mushroom",MushroomToppingile sarmalar
Tüm malzemeleri uyguladıktan sonra, son pizzanın açıklamasını ve fiyatını şu formatta yazdırın:
[description] = $[price]Fiyatı iki ondalık basamak olacak şekilde formatlayın.
Aynı malzemenin birden fazla kez nasıl uygulanabildiğine dikkat edin — çift peynir sipariş etmek, sadece CheeseTopping ile iki kez sarmalamak anlamına gelir. Bu esneklik, Decorator Deseninin gücüdür!
Kopya kağıdı
Decorator Pattern (Dekoratör Deseni), nesneleri çalışma zamanında dekoratör nesneleri içine sararak onlara dinamik olarak davranışlar ekleyen yapısal bir tasarım desenidir.
Hem temel nesne hem de dekoratörler aynı arayüzü uygular:
<?php
interface Coffee {
public function getDescription(): string;
public function getCost(): float;
}
class SimpleCoffee implements Coffee {
public function getDescription(): string {
return "Simple Coffee";
}
public function getCost(): float {
return 2.00;
}
}
Dekoratörler, aynı arayüz tipindeki başka bir nesneyi sarar:
<?php
class MilkDecorator implements Coffee {
public function __construct(private Coffee $coffee) {}
public function getDescription(): string {
return $this->coffee->getDescription() . ", Milk";
}
public function getCost(): float {
return $this->coffee->getCost() + 0.50;
}
}
class SugarDecorator implements Coffee {
public function __construct(private Coffee $coffee) {}
public function getDescription(): string {
return $this->coffee->getDescription() . ", Sugar";
}
public function getCost(): float {
return $this->coffee->getCost() + 0.25;
}
}
Davranışları birleştirmek için dekoratörleri zincirleyin:
$coffee = new SimpleCoffee();
$coffee = new MilkDecorator($coffee);
$coffee = new SugarDecorator($coffee);
echo $coffee->getDescription() . " = $" . $coffee->getCost();
// Çıktı: Simple Coffee, Milk, Sugar = $2.75
Dekoratörler, her kombinasyon için yeni sınıflar oluşturmaya gerek kalmadan birden fazla kez ve herhangi bir sırada uygulanabilir.
Kendin dene
<?php
require_once 'BasePizza.php';
require_once 'Toppings.php';
// Girdiyi oku - virgülle ayrılmış malzeme listesi
$input = trim(fgets(STDIN));
$toppings = explode(',', $input);
// Temel bir MargheritaPizza ile başla
$pizza = new MargheritaPizza();
// TODO: Her bir malzeme üzerinden döngü kurun ve pizzayı uygun dekoratör ile sarmalayın
// - "cheese" -> CheeseTopping ile sarmala
// - "pepperoni" -> PepperoniTopping ile sarmala
// - "mushroom" -> MushroomTopping ile sarmala
// TODO: Sonucu şu formatta yazdırın: [description] = $[price]
// number_format() kullanarak fiyatı 2 ondalık basamak olacak şekilde biçimlendirin
?>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
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesneler$this Anahtar KelimesiMetotlarÖzelliklerYapıcı Metot (__construct)Yıkıcı Metot (__destruct)Özet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtımparent:: Anahtar KelimesiMetot Geçersiz Kılmafinal Anahtar KelimesiSoyut SınıflarÖzet - Çalışan Hiyerarşisi7Kapsülleme
Public, Protected, PrivateErişim Belirleyicilere Derinlemesine BakışGetter ve Setter MetotlarıBilgi GizlemeConstructor Promotion (8.0)Özet - Öğrenci Kayıt Sistemi10İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımDependency InjectionAnonim SınıflarEnum'lar (PHP 8.1)Fiber'lar (PHP 8.1)Nesne Klonlama: Derinlemesine İncelemeGenerator'lar ve Iterator'lar13Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıRepository Kalıbı2İsim Alanları ve Autoloading
İsim Alanlarına Girişuse Anahtar KelimesiPSR-4 Autoloading StandartıComposer AutoloaderÖzet - Düzenli Proje5Arayüzler ve Sözleşmeler
Arayüzlere GirişArayüzleri UygulamaBirden Fazla Arayüz UygulamaArayüz vs Soyut SınıfArayüzler ile Tip BelirlemeÖzet - Şekil Hesaplayıcı8Sihirli Metotlar
Sihirli Metotlara Giriş__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Nesne Klonlama__serialize & __unserializeÖzet - Özel Koleksiyon3Sınıf Özellikleri
Örnek ve Statik ÖzelliklerSınıflarda SabitlerStatik Metotlar ve ÖzelliklerPrivate ve Protected ÖzelliklerReadonly Özellikler (PHP 8.1)Özet - Banka Hesabı Yöneticisi6Çok Biçimlilik
Metot Geçersiz Kılmaya Yeniden BakışArayüzler ile Çok BiçimlilikType Hinting ve Union TypesLate Static BindingÖzet - Ödeme İşlemcisi9Trait'ler
Trait'lere GirişÇoklu Trait KullanımıTrait Çakışma ÇözümüTrait'lerde Soyut MetotlarTrait'ler ve Kalıtım12Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıObserver KalıbıStrategy Kalıbı15Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi