Menu
Coddy logo textTech

Dekoratör Kalıbı

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

Dekoratör Deseni (Decorator Pattern), nesneleri dekoratör adı verilen özel nesnelerin içine sararak onlara 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 orijinal sınıfı değiştirmeden çalışma zamanında dinamik olarak işlevsellik ekler.

Temel bir kahve ile başladığınız ve süt, şeker veya krem şanti gibi ekstralar ekleyebildiğiniz bir kahve dükkanı hayal edin. Her ekleme, orijinal kahveyi sarmalar, maliyetini ve açıklamasını ekler. Bu desen, dekore edilmiş nesnelerin orijinaliyle aynı şekilde ele alınabilmesi için ortak bir arayüz kullanır:

interface Coffee {
    String getDescription();
    double getCost();
}

class SimpleCoffee implements Coffee {
    public String getDescription() {
        return "Simple Coffee";
    }
    public double getCost() {
        return 2.0;
    }
}

abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}

class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }
    
    public double getCost() {
        return coffee.getCost() + 0.5;
    }
}

Dekoratör, sarmalanmış nesneye bir referans tutar ve kendi davranışını eklerken çağrıları ona devreder. Özellikleri birleştirmek için birden fazla dekoratörü üst üste ekleyebilirsiniz:

Coffee order = new SimpleCoffee();
order = new MilkDecorator(order);
order = new SugarDecorator(order);

System.out.println(order.getDescription());  // Sade Kahve, Süt, Şeker
System.out.println(order.getCost());         // 2.75

Dekoratör Deseni (Decorator Pattern), alt sınıfların aşırı artışına neden olmadan nesnelere sorumluluklar eklemeniz gerektiğinde öne çıkar. Her bir dekoratör bağımsızdır, bu nedenle tam olarak ihtiyacınız olan davranış kombinasyonunu oluşturmak için onları özgürce karıştırıp eşleştirebilirsiniz.

challenge icon

Görev

Kolay

Decorator Desen Kalıbını kullanarak bir bildirim sistemi oluşturalım! Dekoratörleri birbirine sarmalayarak farklı teslimat kanallarıyla (e-posta uyarıları, SMS uyarıları ve anlık bildirimler) geliştirilebilen temel bir bildirim oluşturacaksınız. Bu, tek bir mesajın aynı anda birden fazla kanal üzerinden gönderilmesi gerekebilen gerçek dünya sistemlerini yansıtır.

Kodunuzu dört dosya halinde düzenleyeceksiniz:

  • Notifier.java: Dekoratör deseniniz için bileşen arayüzü (component interface) görevi gören Notifier arayüzünü tanımlayın. Bildirimlerin gönderilmesini sağlayan bir send(String message) metodu bildirmelidir.
  • BasicNotifier.java: Notifier arayüzünü uygulayan somut bileşen (concrete component) sınıfını oluşturun. Bu, bildirimin en basit halini — bir uygulama içi (in-app) uyarıyı — temsil eder. send metodu çağrıldığında, "In-App: " + message çıktısını yazdırmalıdır.
  • NotifierDecorators.java: Dekoratör hiyerarşinizi burada oluşturun. Notifier arayüzünü uygulayan ve sarmalanmış bir Notifier nesnesine (yapıcı metot aracılığıyla aktarılan) referans tutan soyut bir NotifierDecorator sınıfı ile başlayın.

    Ardından NotifierDecorator sınıfını genişleten üç somut dekoratör oluşturun:

    EmailDecorator - send çağrıldığında, önce sarmalanmış bildirimciye (wrapped notifier) delege eder, ardından "Email: " + message yazdırır.

    SMSDecorator - send çağrıldığında, önce sarmalanmış bildirimciye delege eder, ardından "SMS: " + message yazdırır.

    PushDecorator - send çağrıldığında, önce sarmalanmış bildirimciye delege eder, ardından "Push: " + message yazdırır.

  • Main.java: Dekoratör sisteminizi bir araya getirin! İki girdi alacaksınız: bildirim mesajı (String) ve eklenecek kanalların virgülle ayrılmış listesi (String), örneğin "email,sms" veya "push,email,sms".

    Bir BasicNotifier ile başlayın. Ardından, kanal girdisine bağlı olarak, onu göründükleri sırayla uygun dekoratörlerle sarmalayın. Geçerli kanal adları "email", "sms" ve "push" şeklindedir.

    Son olarak, tam olarak dekore edilmiş bildirimci üzerinde mesajınızla birlikte send metodunu çağırın.

Sırasıyla iki girdi alacaksınız: gönderilecek mesaj (String) ve etkinleştirilecek kanallar (String, virgülle ayrılmış).

Örneğin, "Server is down!" ve "email,push" girdileriyle çıktınız şu şekilde olacaktır:

In-App: Server is down!
Email: Server is down!
Push: Server is down!

Her dekoratörün orijinal bildirimi korurken kendi davranışını nasıl eklediğine dikkat edin. Sarmalama sırası çıktı sırasını belirler — en içteki bileşen (BasicNotifier) önce çalışır, ardından her dekoratör kendi katmanını ekler. Her kombinasyon için ayrı sınıflar oluşturmadan herhangi bir kanal kombinasyonunu karıştırıp eşleştirebilirsiniz!

Kopya kağıdı

Decorator Pattern (Dekoratör Deseni), nesneleri dekoratör nesneleri içine sararak onlara yeni davranışlar ekleyen yapısal bir tasarım desenidir. Orijinal sınıfı değiştirmeden çalışma zamanında dinamik olarak işlevsellik ekler.

Desen ortak bir arayüz kullanır, böylece dekore edilmiş nesneler orijinal nesne ile aynı şekilde ele alınabilir.

Temel Yapı

Bir bileşen arayüzü tanımlayın:

interface Coffee {
    String getDescription();
    double getCost();
}

Arayüzü uygulayan somut bir bileşen oluşturun:

class SimpleCoffee implements Coffee {
    public String getDescription() {
        return "Simple Coffee";
    }
    public double getCost() {
        return 2.0;
    }
}

Aynı arayüzü uygulayan ve sarılmış nesneye bir referans tutan soyut bir dekoratör sınıfı oluşturun:

abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}

Soyut dekoratörü genişleten somut dekoratörler oluşturun:

class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }
    
    public double getCost() {
        return coffee.getCost() + 0.5;
    }
}

Dekoratörleri Kullanma

Özellikleri birleştirmek için birden fazla dekoratörü üst üste ekleyin:

Coffee order = new SimpleCoffee();
order = new MilkDecorator(order);
order = new SugarDecorator(order);

System.out.println(order.getDescription());  // Simple Coffee, Milk, Sugar
System.out.println(order.getCost());         // 2.75

Dekoratör, kendi davranışını eklerken çağrıları sarılmış nesneye iletir. Her dekoratör bağımsızdır ve serbestçe karıştırılıp eşleştirilebilir.

Kendin dene

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Gönderilecek mesajı oku
        String message = scanner.nextLine();
        
        // Virgülle ayrılmış kanal listesini oku (örneğin, "email,sms" veya "push,email,sms")
        String channelsInput = scanner.nextLine();
        
        // TODO: Bir BasicNotifier ile başla
        
        // TODO: Kanallar girdisini virgülle ayır
        
        // TODO: Her bir kanal üzerinde döngü kur ve bildirimciyi uygun dekoratör ile sarmala
        // Geçerli kanallar: "email", "sms", "push"
        
        // TODO: Tamamen dekore edilmiş bildirimci üzerinde mesaj ile send metodunu çağı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