Decorator Pattern Nedir ve Nasıl Kullanılır?

Decorator Pattern, nesnelerin yapısını değiştirmeden davranışlarını dinamik olarak eklememizi sağlar. Bu yapısal desen, dekoratör sınıflarıyla nesnelerin işlevselliğini artırmamızı sağlar. Bu nedenle, bu yazıda Decorator Pattern’ı bir örnekle açıklayacağım.

Decorator Pattern Neden Kullanılır?

Decorator tasarım deseni, işlevselliği genişletmek için alt sınıflandırmaya esnek bir alternatif sunar. Farklı davranış kombinasyonları için birden fazla alt sınıf oluşturmak yerine, dekoratörlerle işlevleri çalışma zamanında karıştırıp eşleştiririz. Böylece, daha temiz ve bakımı kolay bir kod elde ederiz.

Decorator Pattern’ın Temel Bileşenleri

  • Component: Çekirdek yöntemleri tanımlayan bir arayüz veya soyut sınıf.
  • ConcreteComponent: Component arayüzünü uygulayan bir sınıf.
  • Decorator: Component arayüzünü uygulayan ve bir Component nesnesine referans tutan bir soyut sınıf.
  • ConcreteDecorator: Decorator sınıfını genişleten ve yeni davranış ekleyen bir sınıf.

Örnek: Kahve Süslemek

Bir kahve dükkanında, bir kahveye çeşitli soslar ekleyebildiğimizi düşünelim. Bu nedenle, bunu göstermek için basit bir yapı oluşturacağız.

1. Adım: Component Tanımla

// Component arayüzü
public interface Coffee {
    String getDescription();
    double getCost();
}

2. Adım: ConcreteComponent Oluştur

// ConcreteComponent
public class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Sade Kahve";
    }

    @Override
    public double getCost() {
        return 20.00;
    }
}

3. Adım: Decorator Uygula

// Decorator
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }

    public String getDescription() {
        return decoratedCoffee.getDescription();
    }

    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

4. Adım: ConcreteDecorators Oluştur

// ConcreteDecorator
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + ", Süt";
    }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost() + 5.00;
    }
}

// Başka bir ConcreteDecorator
public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + ", Şeker";
    }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost() + 2.00;
    }
}

5. Adım: Dekoratörleri Kullan

public class CoffeeShop {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + " ₺" + coffee.getCost());

        coffee = new MilkDecorator(coffee);
        System.out.println(coffee.getDescription() + " ₺" + coffee.getCost());

        coffee = new SugarDecorator(coffee);
        System.out.println(coffee.getDescription() + " ₺" + coffee.getCost());
    }
}

Decorator Pattern’in Avantajları ve Dezavantajları

Decorator Pattern, nesne yönelimli programlamada sıkça kullanılan ve birçok duruma uygun olan bir desendir. Ancak, her tasarım deseninde olduğu gibi, Decorator Pattern’in de avantajları ve dezavantajları vardır. İşte bunlar:

Avantajları

  1. Esneklik ve Genişletilebilirlik:
    • Decorator Pattern kullanarak, nesnelerin davranışlarını çalışma zamanında dinamik olarak değiştirebiliriz. Bu yaklaşım, esnek bir tasarım sağlar ve nesnelerin genişletilmesini kolaylaştırır.
    • Yeni işlevsellik eklemek için var olan kodu değiştirmek yerine yeni dekoratörler oluştururuz. Böylece, mevcut kod tabanını korur ve genişletebiliriz.
  2. Tek Sorumluluk Prensibi:
    • Her dekoratör sınıfı, kendisine özgü bir işlevselliği ekleyerek tek sorumluluk prensibini korur. Bu da sonuç olarak sınıfların daha yönetilebilir ve anlaşılır olmasını sağlar.
  3. Kod Tekrarını Azaltma:
    • Decorator Pattern, farklı kombinasyonlardaki işlevsellikleri uygulamak için alt sınıflandırma yerine dekoratörleri kullanır. Böylece, kod tekrarını azaltır.
  4. Açık/Kapalı Prensibi (Open/Closed Principle):
    • Yeni özellikler eklemek için mevcut kodu değiştirmeye gerek kalmadan, sınıfları genişletmek mümkündür. Bu da yazılımın bakımı ve genişletilmesini kolaylaştırır.

Dezavantajları

  1. Kod Karmaşıklığı:
    • Decorator Pattern kullanarak birçok küçük sınıf ve nesne yaratabiliriz. Bu durum, kod tabanını daha karmaşık ve izlenmesi zor hale getirebilir.
    • Dekoratör zincirleri oluşturduğumuzda, özellikle uzun zincirler söz konusu olduğunda, kodun anlaşılması zorlaşır.
  2. Performans:
    • Her dekoratör ek bir nesne oluşturur ve her bir nesne üzerinden yöntem çağrıları yaparız. Bu durum performans üzerinde küçük bir etki yaratacaktır. Ancak, genellikle modern sistemlerde bu etki ihmal edilebilir düzeydedir.
  3. Hata Ayıklama Zorluğu:
    • Hangi dekoratörlerin bir nesneye uygulandığını ve hangi sırayla uygulandığını izlemek zor olabilir. Dolayısıyla, bu durum hata ayıklamayı ve sorun gidermeyi zorlaştırır.
  4. Çok Katmanlı Dekoratörler:
    • Çok sayıda dekoratör kullandığımızda, bir nesnenin nihai davranışını anlamak zor olabilir. Bu nedenle, her katmanın eklediği işlevselliği ve değiştirdiği davranışları dikkatle takip etmeliyiz.

Sonuç

Decorator Pattern, nesne davranışlarını esnek ve dinamik bir şekilde genişletmemize olanak tanır. Örneğin, kahve dükkanı senaryomuzda, yeni soslar eklemek için kolayca yeni dekoratörler oluştururuz. Bu desen, kod tekrarını azaltır ve kod tabanımızı daha sağlam ve bakımı daha kolay hale getirerek Açık/Kapalı Prensibini korur.

Decorator Pattern, esneklik ve genişletilebilirlik sağlayan güçlü bir desendir. Ancak, dikkatli kullanılmadığında karmaşıklık ve performans sorunlarına yol açar. Bu nedenle, tasarım kararları verirken bu avantajları ve dezavantajları göz önünde bulundurmak önemlidir.

Paylaşmak ister misin?

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir