Menu
Coddy logo textTech

Dekoratör Kalıbı

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 98 / 104.

Decorator kalıbı, nesneleri dekoratör adı verilen özel nesnelere sararak onlara dinamik olarak yeni davranışlar eklemenizi sağlar. Derleme zamanında davranış ekleyen kalıtımın aksine dekoratörler, özgün sınıfı değiştirmeden işlevselliği çalışma zamanında genişletmenize olanak tanır.

Bu desen, hem özgün nesnenin hem de dekoratörlerin aynı arayüzü uygulamasıyla çalışır. Her dekoratör bir bileşene başvuru tutar ve sarmalanan nesneye devretmeden önce veya devrettikten sonra kendi davranışını ekler:

#include <iostream>
#include <memory>

// Bileşen arayüzü
class Coffee {
public:
    virtual std::string getDescription() const = 0;
    virtual double getCost() const = 0;
    virtual ~Coffee() = default;
};

// Somut bileşen
class SimpleCoffee : public Coffee {
public:
    std::string getDescription() const override { return "Coffee"; }
    double getCost() const override { return 2.0; }
};

// Temel dekoratör
class CoffeeDecorator : public Coffee {
protected:
    std::unique_ptr<Coffee> coffee;
public:
    CoffeeDecorator(std::unique_ptr<Coffee> c) : coffee(std::move(c)) {}
};

// Somut dekoratörler
class MilkDecorator : public CoffeeDecorator {
public:
    MilkDecorator(std::unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}
    std::string getDescription() const override {
        return coffee->getDescription() + ", Milk";
    }
    double getCost() const override { return coffee->getCost() + 0.5; }
};

class SugarDecorator : public CoffeeDecorator {
public:
    SugarDecorator(std::unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}
    std::string getDescription() const override {
        return coffee->getDescription() + ", Sugar";
    }
    double getCost() const override { return coffee->getCost() + 0.2; }
};

Decorator'lar üst üste eklenebilir; her biri bir öncekini sararak işlevselliği katman katman oluşturur:

int main() {
    std::unique_ptr<Coffee> order = std::make_unique<SimpleCoffee>();
    order = std::make_unique<MilkDecorator>(std::move(order));
    order = std::make_unique<SugarDecorator>(std::move(order));
    
    std::cout << order->getDescription() << ": $" << order->getCost();
    // Çıktı: Coffee, Milk, Sugar: $2.7
}

Decorator'ı, diğer nesneleri etkilemeden nesnelere dinamik olarak sorumluluklar eklemeniz gerektiğinde veya işlevselliği alt sınıflandırma yoluyla genişletmenin sınıfların aşırı artmasına yol açacağı durumlarda kullanın.

challenge icon

Görev

Kolay

Decorator desenini kullanarak bir Pizza Sipariş Sistemi oluşturalım. Müşterilerin temel bir pizzayla başlayıp çeşitli malzemeler ekleyebileceği esnek bir sistem oluşturacaksınız: her malzeme önceki siparişi sarar ve kendi maliyetini ve açıklamasını ekler. Bu, dekoratörler için mükemmel bir kullanım alanıdır: alt sınıfların patlamasına yol açmadan malzemeler herhangi bir kombinasyonla üst üste eklenebilir.

Kodunuzu üç dosyaya ayıracaksınız:

  • Pizza.h: Bileşen arayüzünü ve temel pizza sınıfını tanımlayın.

    Saf sanal Pizza (bir string döndürür) ve getDescription() (bir double döndürür) metotlarına ve sanal bir yıkıcıya sahip soyut bir getCost() sınıfı oluşturun.

    Ardından temel pizzayı temsil eden somut bir PlainPizza sınıfı oluşturun. Bu sınıf, açıklaması olarak "Pizza" döndürmeli ve temel maliyeti 8.0 olmalıdır.

  • ToppingDecorator.h: Dekoratör temel sınıfını ve somut malzeme dekoratörlerini oluşturun.

    ToppingDecorator sınıfından kalıtım alan ve sarılan bileşen için bir Pizza tutan bir std::unique_ptr<Pizza> sınıfı oluşturun. Bu sınıf, tüm malzeme dekoratörleri için temel görevi görür.

    Üç somut malzeme dekoratörü uygulayın:

    • CheeseTopping: açıklamaya ", Cheese" ve maliyete 1.5 ekler
    • PepperoniTopping: açıklamaya ", Pepperoni" ve maliyete 2.0 ekler
    • MushroomTopping: açıklamaya ", Mushrooms" ve maliyete 1.0 ekler

    Her dekoratör, sarılan pizzaya devretmeli ve ardından kendi katkısını eklemelidir.

  • main.cpp: Kullanıcı girdisine göre özelleştirilmiş bir pizza siparişi oluşturun.

    Üç girdi okuyun (her biri yes veya no olacaktır):

    1. Peynir eklensin mi?
    2. Pepperoni eklensin mi?
    3. Mantar eklensin mi?

    Bir PlainPizza ile başlayın, ardından girdilere göre uygun malzeme dekoratörleriyle (sırasıyla: peynir, pepperoni, mantar) sarın. Son olarak sipariş ayrıntılarını şu biçimde yazdırın:

    Order: [description]
    Total: $[cost]

Örneğin, girdiler yes, yes, no olduğunda:

Order: Pizza, Cheese, Pepperoni
Total: $11.5

Girdiler yes, no, yes olduğunda:

Order: Pizza, Cheese, Mushrooms
Total: $10.5

Girdiler no, no, no olduğunda:

Order: Pizza
Total: $8

Girdiler yes, yes, yes olduğunda:

Order: Pizza, Cheese, Pepperoni, Mushrooms
Total: $12.5

Her dekoratörün bir öncekini sararak hem açıklamayı hem de maliyeti katman katman oluşturduğuna dikkat edin. Mevcut pizza veya malzeme kodunu değiştirmeden yeni dekoratör sınıfları oluşturarak kolayca yeni malzemeler ekleyebilirsiniz: Decorator deseninin güzelliği budur.

Kendin dene

#include <iostream>
#include <string>
#include <memory>
#include "Pizza.h"
#include "ToppingDecorator.h"

using namespace std;

int main() {
    // Üç girdi oku (yes veya no)
    string addCheese, addPepperoni, addMushrooms;
    cin >> addCheese;
    cin >> addPepperoni;
    cin >> addMushrooms;
    
    // TODO: std::unique_ptr kullanarak bir PlainPizza ile başla
    
    // TODO: Eğer addCheese "yes" ise, pizzayı CheeseTopping ile sar
    
    // TODO: Eğer addPepperoni "yes" ise, pizzayı PepperoniTopping ile sar
    
    // TODO: Eğer addMushrooms "yes" ise, pizzayı MushroomTopping ile sar
    
    // TODO: Siparişi şu formatta yazdır:
    // Order: [description]
    // Total: $[cost]
    
    return 0;
}
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 C++ derleyicisi