C++, Uml
No Comments The Decorator Pattern
Bu yazımızda structural bir pattern olan decorator patternini anlatacağız. Bu tasarım kalıbı 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. Yani bir nesneye alt sınıflar yaratılmaksızın, dinamik olarak yeni özellikler kazandırmak için kullanılır.
Şimdi gerçek hayattan bir örnekle yapacağımız işi anlatmaya çalışacağım. Örneğimizi anlatırken gerekli sınıflarımızı çıkarmaya çalışalım daha sonrada bu patterni nerelerde kullanabiliriz ona bakalım.
Starbuzz Coffee de kahve içmeye gittiğimizi düşünelim ve kahvemiz için malzemelerimizi belirliyoruz ve seçtiğimiz malzemelere göre aldığımız kahvenin fiyatı belirlenecek olsun . Doğal olarak kahvenin fiyatı, seçtiğimiz malzemelere göre değişkenlik gösterecektir.
Şimdi bu durumu modelleyelim. Hazırlanacak olan tüm kahvelerimizi kapsayacak bir interface yada abstract sınıfa ihtiyacımız olacak çünkü tüm malzemelerimizin ortak bir yanı var, oda hepsi kahve için kullanılan malzemeler ve hepsinin bir ücreti var. O zaman Beverage adını verdiğimiz bir interface yada abstract bir sınıf tanımlayalım ve bununda ücret ve aciklama adında abstract bir metodu olsun. Bu metodun kendisi ,bu sınıf yada interfaceden türemiş tüm sınıflarda ovveride edilecek ve ilgili malzemenin fiyatını verecektir. Fakat burda bir tanede ana objemiz var yani dekore edilecek objemiz oda kahveyi hazırlamamız için gerekli kahve tüm malzemelerimiz bu kahvenin üzerine eklenecek ve sonuç olarak bir fiyat belirleyeceğiz. Biz bu objemizi örneğimizde kahve olarak tanımlayacağız.
Ortak özelliklere sahip objelerimiz var ve biz ana objemizi sırasıyla istediğimiz malzemeyle dekore edeceğiz ve bu dekorasyon sonucunda ucret fonksiyonunu çagırarak işlemin sonucunu görebileceğiz
Dolayısıyla öncelikle kahve nesnesine ihtiyacımız olacak. Bu nesnemizin bir fiyatı olacağından Beverage interfaceinden türemiş bir sınıf olacak, daha sonra ise kahvemizi dekore edecek nesnelere ihtiyacımız var ve bu objelerimizinde bir ücreti olacağından aynı interfaceden türeteceğiz fakat aynı zamanda her dekorasyonda elde edilecek ücretin bir önceki dekorasyonun üzerine eklenmesi için Beverage interfaceini bir eleman olarak dekoratorlerimizde tanımlayacağız. Öncelikle Dekorator patternimize ait tasarımı bir uml şeması üzerinde görelim.
·Component : Dinamik olarak sorumluklar eklenebilecek olan asıl nesne için sunulan arayüzdür. Interface veya abstract sınıf olarak tasarlanabilir.
·ConcreteComponent : Sorumlulukların dinamik olarak eklenebilecekleri asıl bileşen sınıflarıdır. Component arayüzünü uyarlarlar ve abstract sınıf olarak tasarlanırlar.
·Decorator : Decorator tipi hem Component arayüzünü uygular hemde kendi içerisinde Component tipinden bir nesne örneği referansını barındırır. Bu sebepten UML şemasındanda görüldüğü gibi Decorator ve Component arasında bir Aggregation ilişkisi mevcuttur.
·ConcreteDecorator: Bileşenlere yeni sorumlulukları eklemekle görevli tiptir. Ek işlevler bu tip içerisinde tanımlanan üyelerdir.
Verdiğimiz örneği düşünürsek Component yerine ucret fonksiyonunu barından Beverage interfaceini veya abstarct sınıfını kullanacağız. Component sınıfına karşılık Kahve sınıfımız olacak ve Decorator sınıfına karşılıkta malzemelerimizi tanımladığımız yine CondimentDecorator türeyen sınıflarımız olacak şimdi uml diagramımıza bakalım ve kodlamaya geçelim.
önce ilgili sınıflarımızın türeyeceği interfaceimizi oluşturalım:
class Beverage{
public:
Beverage(){description=”Unkonown Beverage”;}
virtual string getDescription()
{return description;}
virtual double cost()=0;
protected:
string description;
};
oluşturduğumuz interfaceden türemiş ana objemizi oluşturalım ve Beverage metodlarını implemente edelim:
class CondimentDecorator:public Beverage{
public:
virtual string getDescription()=0;
};
Abstract sınıftan türeteceğimiz kahve çeşitlerini ve metotlarını türetelim:
class Expresso:public Beverage{
public:
Expresso(){description=”Expresso”;}
double cost(){return 1.99;}
};
class HouseBlend:public Beverage{
public:
HouseBlend(){description=”House Blend Coffee”;}
double cost(){return .89;}
};
class DarkRoast:public Beverage{
public:
DarkRoast(){description=”Dark Roast Coffee”;}
double cost(){return .99;}
};
class Decaf:public Beverage{
public:
Decaf(){description=”Decaf Coffee”;}
double cost(){return 1.05;}
};
Şimdi’de malzemelerimizi oluşturmaya başlayabiliriz.Tüm malzemeler Beverage intefacesinden bir örneği içerecek ve malzemelerin hepsi CondimentDecorator sınıfından türeyecektir.
class SteamedMilk:public CondimentDecorator{
public:
SteamedMilk(Beverage *beverage)
{this->beverage=beverage;}
string getDescription()
{return beverage->getDescription()+”, Steamed Milk”;}
double cost()
{return .10+beverage->cost();}
private:
Beverage *beverage;
};
class Mocha:public CondimentDecorator{
public:
Mocha(Beverage *beverage)
{this->beverage=beverage;}
string getDescription()
{return beverage->getDescription()+”, Mocha”;}
double cost()
{return .20+beverage->cost();}
private:
Beverage *beverage;
};
class Soy:public CondimentDecorator{
public:
Soy(Beverage *beverage)
{this->beverage=beverage;}
string getDescription()
{return beverage->getDescription()+”, Soy”;}
double cost()
{return .15+beverage->cost();}
private:
Beverage *beverage;
};
class Whip:public CondimentDecorator{
public:
Whip(Beverage *beverage)
{this->beverage=beverage;}
string getDescription()
{return beverage->getDescription()+”, Whip”;}
double cost()
{return .10+beverage->cost();}
private:
Beverage *beverage;
};
gödüğünüz gibi yeni bir malzeme eklemek istediğimiz zaman CondimentDecorator interfaceinden türeyen ve bu interface i içeren bir sınıf eklememiz yeterli olacaktır. Yazdığımız modeli şekillerle göstermek gerekirse

yukardaki şekilde en dıştaki ücret fonksiyonunu çağırdığımız zaman en içteki ücret fonksiyonuna kadar tüm ücret fonksiyonları birbirini çagıracak ve karşımıza toplam sonuç gelecektir şimdi tüm bu tasarımın sonuçlarını görelim.
int main(){
Beverage *beverage=new Expresso;
cout<<beverage->getDescription()+” $”<<beverage->cost()<<endl;
Beverage *beverage2=new DarkRoast;
beverage2=new Mocha(beverage2);
beverage2=new Mocha(beverage2);
beverage2=new Whip(beverage2);
cout<<beverage2->getDescription()+” $”<<beverage2->cost()<<endl;
Beverage *beverage3=new HouseBlend;
beverage3=new Soy(beverage3);
beverage3=new Mocha(beverage3);
beverage3=new Whip(beverage3);
cout<<beverage3->getDescription()+” $”<<beverage3->cost()<<endl;
return 0;
}












