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.75Dekoratö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.
Görev
KolayDecorator 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örenNotifierarayüzünü tanımlayın. Bildirimlerin gönderilmesini sağlayan birsend(String message)metodu bildirmelidir.BasicNotifier.java:Notifierarayü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.sendmetodu çağrıldığında,"In-App: " + messageçıktısını yazdırmalıdır.NotifierDecorators.java: Dekoratör hiyerarşinizi burada oluşturun.Notifierarayüzünü uygulayan ve sarmalanmış birNotifiernesnesine (yapıcı metot aracılığıyla aktarılan) referans tutan soyut birNotifierDecoratorsınıfı ile başlayın.Ardından
NotifierDecoratorsı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: " + messageyazdırır.SMSDecorator-sendçağrıldığında, önce sarmalanmış bildirimciye delege eder, ardından"SMS: " + messageyazdırır.PushDecorator-sendçağrıldığında, önce sarmalanmış bildirimciye delege eder, ardından"Push: " + messageyazdı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
BasicNotifierile 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
sendmetodunu ç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.75Dekoratö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
}
}
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 Nesnelerthis Anahtar KelimesiMetotlarAlanlar (Öznitelikler)Yapıcı MetotYapıcı Metot Aşırı YüklemeÖzet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtım (extends)super Anahtar KelimesiMetot Geçersiz Kılma (@Override)Yapıcı Metot ZincirlemeObject SınıfıTekli ve Çok Seviyeli KalıtımNeden Çoklu Sınıf Kalıtımı Yok?Özet - Çalışan Hiyerarşisi7Özel Metotlar ve Object Sınıfı
toString() Metoduequals() ve hashCode()clone() MetoducompareTo() ve ComparableComparator ArayüzüÖzet - Özel Sıralama2Erişim Belirleyiciler ve Kapsülleme
Erişim Seviyelerine Genel BakışGetter ve Setter MetotlarıBilgi Gizlemefinal Anahtar KelimesiÖzet - Banka Hesabı Yöneticisi5Polimorfizm
Metot Aşırı Yükleme TemelleriMetot Geçersiz Kılma (Çalışma Zamanı)Upcasting ve Downcastinginstanceof OperatörüSoyut Sınıflar ve MetotlarÖzet - Şekil Hesaplayıcı8İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımAgregasyon vs KompozisyonDahili, Yuvalanmış ve Anonim SınıflarEnum'lar ve Enum MetotlarıRecords (Java 16+)Sealed Classes (Java 17+)11Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıBuilder KalıbıObserver KalıbıStrategy Kalıbı14Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi3Sınıf Özellikleri ve Statik Üyeler
Instance ve Statik DeğişkenlerStatik MetotlarStatik BloklarSabitler (static final)Özet - Sayaç ve Utility6Arayüzler ve Soyut Sınıflar
Arayüzlere GirişArayüzleri UygulamaÇoklu Arayüz UygulamaArayüzlerde Default ve StaticSoyut Sınıflar ve ArayüzlerFonksiyonel ArayüzlerÖzet - Ödeme Sistemi9Generics
Generics'e GirişGeneric SınıflarGeneric MetotlarSınırlandırılmış Tip ParametreleriWildcard'lar (?, extends, super)Özet - Generic Container12Tasarı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ıYineleyici Kalıbı