C# Decorator Pattern Kullanımı - OOP Design Pattern



Decorator tasarım deseni; structural grubuna ait bir desen olup Dofactory.com a göre kullanım sıklığı %60 civarındadır.

Decorator tasarım deseni bir nesneye dinamik olarak yeni sorumlulukların eklenmesi ve hatta var olanların çıkartılması amacıyla kullanılır. Bir açıdan bakıldığında nesneyi kendisinden türeyen alt sınıflar ile genişletmek yerine kullanılabilen alternatif bir yaklaşım olarak düşünülebilir.



Bir örnek üzerinden incelersek örneğin otomobil satış programı yazıyoruz.  Bu otomobil nesnemizi istediğimiz şekilde dekore edebiliriz. ABS, Hava yastığı vb. gibi özellikler ekleyebiliriz ve çıkarabiliriz. Bu özelliklere gore alacağımız otomobilin fiyatının değişmesi gerekiyor.

Çözüm 1: 

Her tülü kombinasyon ile otomobil sınıfları yaratma CarWithABS,CarWithAirbag.. böyle uzayıp giden bir liste, aynı zamanda yeni bir özellik gelince yeniden sınıf yaratma zahmeti bunun güzel bir çözüm olmadığını sizde görmüşsünüzdür.

Çözüm 2:

    public interface ICar
    {
        string Model { get; set; }
        string Brand { get; set; }
        decimal Price { get; set; }

        bool HasABS { get; set; }
        bool HasAirbag { get; set; }
    }

ICar adında bir interface oluşturup özellikler için bool değerler tuabiliriz. Ama burda da sorun var çünkü yeni bir özellik gelince ne yapılacak? ICar interface’imizin değişmesi gerekiyor. Buradaki problem önemli bir yazılım prensibinden uzak olmamız oda “open-closed” prensibi yani yazıdğımız interface halen son şeklini almış değil ve yeni özellik gelmesi durumunda hem sınıfımızı değiştirmek zorunda kalacağız hemde türeyen sınıflarda bu düzeltmeleri yapmamız gerekecek. “open-closed” prensibine göre yazılımlarımızın değişime kapalı gelişime açık olması gerekmektedir.

Çözüm 3:

Geldik sonunda Decorator tasarım deseni ile bu sorunu nasıl çözeceğimize. Bu özellikleri otomobilimize ekleyecek decorator sınıflarını oluştururuz. Örneğin ABSDecorator, AirbagDecarotor.. bu decorator sınıfları arabamızı dekore etmemiz sağlıyacak ve her eklediğimiz özellik için fiyatını hesaplayacak. Bununla birlikte örneğimize olmayacak ama şöyle bişide olabilirdi. Decorator ile nesnemize yeni bir şey yapabilme özelliği sağlayabilirdik. Örneğin sunroof decoratorumuz olsaydı UstunuAc() diye bir metodu artık çalıştırabilir hale gelecekti nesnemiz.

Örnek programımıza geçersek:

UML Diagramı:


Kod:

    public interface ICarDecarotor
    {
        void PrintDetail();
        void AddPrice(decimal addedPrice);
        void AddDescription(string addedDesc);
    }

    public class Car:ICarDecarotor
    {
        public string Model { get; set; }
        public string Brand { get; set; }
        public decimal Price { get; set; }
        public string Description { get; set; }

        public Car()
        {
            Price = 10.6m;
        }

        public void PrintDetail()
        {
            Console.WriteLine(Description);
        }

        public void AddPrice(decimal addedPrice)
        {
            Price += addedPrice;
        }

        public void AddDescription(string addedDesc)
        {
            Description = "Model: " + Model + " Brand: " + Brand + " Current Price: " + Price.ToString() + " " + addedDesc;
        }
    }

   public class CarDecoratorBase:ICarDecarotor
    {
        internal ICarDecarotor Car;
        public CarDecoratorBase(ICarDecarotor car)
        {
            Car = car;
        }
        public virtual void PrintDetail()
        {
            Car.PrintDetail();
        }

        public virtual void AddPrice(decimal addedPrice)
        {
            Car.AddPrice(addedPrice);
        }

        public virtual void AddDescription(string addedDesc)
        {
            Car.AddDescription(addedDesc);
        }
    }

    public class ABSDecorator:CarDecoratorBase
    {
        public ABSDecorator(ICarDecarotor car)
            : base(car)
        {
        }

        public override void PrintDetail()
        {
            base.Car.AddPrice(6.1m);
            base.Car.AddDescription("ABS added to current car.");
            base.Car.PrintDetail();
        }
    }

    public class AirbagDecarotor:CarDecoratorBase
    {
        public AirbagDecarotor(ICarDecarotor car)
            : base(car)
        {
        }

        public override void PrintDetail()
        {
            base.Car.AddPrice(3.4m);
            base.Car.AddDescription("Airbag added to current car.");
            base.Car.PrintDetail();
        }
    }

        static void Main(string[] args)
        {
            Car car = new Car() { Model = "Astra", Brand = "Opel", Price=35.1m,Description="New car added." };
            car.PrintDetail();

            //nesnemize airbag özelliği ekleniyor
            AirbagDecarotor carWithairbag = new AirbagDecarotor(car);
            carWithairbag.PrintDetail();

            //nesnemize abs özelliği ekleniyor
            ABSDecorator carWithABS = new ABSDecorator(car);
            carWithABS.PrintDetail();

            Console.ReadLine();
        }



0 yorum :

Yorum Gönder