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 58 / 70.

Decorator deseni, nesneleri dekoratör adı verilen özel nesnelerin içine sararak onlara yeni davranışlar eklemenizi sağlayan yapısal bir desendir. Derleme zamanında davranış ekleyen kalıtımın aksine, dekoratörler orijinal sınıfı değiştirmeden çalışma zamanında dinamik olarak işlevsellik ekler.

Bu desen, dekoratörlerin sardıkları nesne ile aynı arayüzü uygulamasını sağlayarak çalışır. Her dekoratör, sarılan nesneye bir referans tutar ve çağrıları ona iletirken, öncesinde veya sonrasında kendi davranışını ekler:

public interface ICoffee
{
    string GetDescription();
    decimal GetCost();
}

public class SimpleCoffee : ICoffee
{
    public string GetDescription() => "Coffee";
    public decimal GetCost() => 2.00m;
}

public abstract class CoffeeDecorator : ICoffee
{
    protected ICoffee _coffee;
    
    public CoffeeDecorator(ICoffee coffee) => _coffee = coffee;
    
    public virtual string GetDescription() => _coffee.GetDescription();
    public virtual decimal GetCost() => _coffee.GetCost();
}

public class MilkDecorator : CoffeeDecorator
{
    public MilkDecorator(ICoffee coffee) : base(coffee) { }
    
    public override string GetDescription() => _coffee.GetDescription() + ", Milk";
    public override decimal GetCost() => _coffee.GetCost() + 0.50m;
}

Dekoratörlerin gücü, üst üste eklenebilme yeteneklerinde yatar. Dekore edilmiş bir nesneyi başka bir dekoratörle sarmalayabilirsiniz:

ICoffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new MilkDecorator(coffee);  // Çift süt!

Console.WriteLine(coffee.GetDescription());  // Kahve, Süt, Süt
Console.WriteLine(coffee.GetCost());         // 3.00

Decorator deseni, alt sınıfların aşırı artmasına neden olmadan nesnelere sorumluluklar eklemeniz gerektiğinde idealdir. Her bir dekoratör tek bir ilgi alanına odaklanır ve tam olarak istediğiniz davranışı oluşturmak için bunları gerektiği gibi birleştirirsiniz.

challenge icon

Görev

Kolay

Decorator desenini kullanarak bir pizza sipariş sistemi oluşturalım. Temel bir pizza oluşturacak ve ardından her bir malzeme önceki katmanı sarmalayarak hem açıklamaya hem de fiyata ekleme yapacak şekilde dinamik olarak malzemeler ekleyeceksiniz.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • Pizza.cs: PizzaShop ad alanında (namespace), dize döndüren GetDescription() ve ondalık sayı (decimal) döndüren GetPrice() adında iki yöntemi olan bir IPizza arayüzü tanımlayın. Ardından bu arayüzü uygulayan bir PlainPizza sınıfı oluşturun - bu sınıf açıklama olarak "Pizza" ve temel fiyat olarak 8.00m döndürmelidir.
  • ToppingDecorators.cs: IPizza arayüzünü uygulayan ve sarmalanmış pizzaya bir referans tutan (yapıcı metot aracılığıyla iletilen) soyut bir ToppingDecorator sınıfı oluşturun. Sanal (virtual) yöntemleri, sarmalanmış pizzaya delege edilmelidir. Ardından üç somut dekoratör oluşturun:
    • CheeseTopping - açıklamaya ", Cheese" ekler ve fiyata 1.50m ekler
    • PepperoniTopping - açıklamaya ", Pepperoni" ekler ve fiyata 2.00m ekler
    • MushroomTopping - açıklamaya ", Mushrooms" ekler ve fiyata 1.25m ekler
  • Program.cs: Sade bir pizza ile başlayıp girdiye göre malzemelerle sarmalayarak her şeyi bir araya getirin. Her malzeme dekoratörü, önceki pizzayı sarmalayarak nihai siparişi katman katman oluşturur.

Bir girdi alacaksınız:

  • Eklenecek malzemelerin virgülle ayrılmış listesi (örneğin, cheese,pepperoni,cheese)

Bir PlainPizza ile başlayın, ardından her malzemeyi göründükleri sırayla uygun dekoratörle sarmalayın. Geçerli malzemeler cheese, pepperoni ve mushrooms şeklindedir. Tüm malzemeleri uyguladıktan sonra, açıklamayı bir satıra ve toplam fiyatı bir sonraki satıra yazdırın.

Örneğin, girdi cheese,pepperoni,mushrooms ise çıktı şöyle olmalıdır:

Pizza, Cheese, Pepperoni, Mushrooms
12.75

Aynı malzemeyi birden fazla kez ekleyebileceğinize dikkat edin! Girdi cheese,cheese ise şunu elde edersiniz:

Pizza, Cheese, Cheese
11

Bu, dekoratör deseninin esnekliğini gösterir - her dekoratör, ister sade bir pizza ister zaten dekore edilmiş bir pizza olsun, aldığı pizzayı sarmalayarak davranışları dinamik olarak üst üste eklemenize olanak tanır!

Kopya kağıdı

Decorator deseni, nesneleri özel dekoratör nesneleri içine sararak onlara yeni davranışlar ekleyen yapısal bir desendir. Orijinal sınıfı değiştirmeden çalışma zamanında dinamik olarak işlevsellik ekler.

Dekoratörler, sardıkları nesneyle aynı arayüzü uygularlar, sarılan nesneye bir referans tutarlar ve kendi davranışlarını eklerken çağrıları ona devrederler:

public interface ICoffee
{
    string GetDescription();
    decimal GetCost();
}

public class SimpleCoffee : ICoffee
{
    public string GetDescription() => "Coffee";
    public decimal GetCost() => 2.00m;
}

public abstract class CoffeeDecorator : ICoffee
{
    protected ICoffee _coffee;
    
    public CoffeeDecorator(ICoffee coffee) => _coffee = coffee;
    
    public virtual string GetDescription() => _coffee.GetDescription();
    public virtual decimal GetCost() => _coffee.GetCost();
}

public class MilkDecorator : CoffeeDecorator
{
    public MilkDecorator(ICoffee coffee) : base(coffee) { }
    
    public override string GetDescription() => _coffee.GetDescription() + ", Milk";
    public override decimal GetCost() => _coffee.GetCost() + 0.50m;
}

Dekoratörler, dekore edilmiş bir nesneyi başka bir dekoratörle sararak üst üste eklenebilir:

ICoffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new MilkDecorator(coffee);  // Çift süt!

Console.WriteLine(coffee.GetDescription());  // Coffee, Milk, Milk
Console.WriteLine(coffee.GetCost());         // 3.00

Çok sayıda alt sınıf oluşturmadan nesnelere sorumluluklar eklemeniz gerektiğinde Decorator desenini kullanın. Her dekoratör tek bir konuya odaklanır ve gerektiğinde birleştirilebilir.

Kendin dene

using System;
using PizzaShop;

class Program
{
    public static void Main(string[] args)
    {
        // Virgülle ayrılmış malzeme listesini oku
        string input = Console.ReadLine();
        string[] toppings = input.Split(',');
        
        // TODO: Bir PlainPizza ile başla
        
        // TODO: Her bir malzeme üzerinde döngü kur ve pizzayı sarmala
        // malzeme adına göre uygun dekoratör ile:
        // - "cheese" -> CheeseTopping
        // - "pepperoni" -> PepperoniTopping
        // - "mushrooms" -> MushroomTopping
        
        // TODO: Nihai açıklamayı ve fiyatı yazdır
    }
}
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