Dekoratör Desenini GOF'ta belgelendiği gibi inceliyordum .
Lütfen Dekoratör Desenini anlamama yardımcı olun . Birisi bunun gerçek dünyada nerede yararlı olduğuna dair bir kullanım örneği verebilir mi?
Dekoratör Desenini GOF'ta belgelendiği gibi inceliyordum .
Lütfen Dekoratör Desenini anlamama yardımcı olun . Birisi bunun gerçek dünyada nerede yararlı olduğuna dair bir kullanım örneği verebilir mi?
Yanıtlar:
Dekoratör deseni, herhangi bir nesneye dinamik olarak sorumluluk eklemek için tek bir hedefe ulaşır.
Bir pizza dükkanı kasasını düşünün. Pizza dükkanında birkaç pizza çeşidi satacaklar ve ayrıca menüde Topingler sağlayacaklar. Şimdi, pizza dükkanının her pizza ve tepesi kombinasyonu için fiyat sağlamak zorunda olduğu bir durumu hayal edin. Dört temel pizza ve 8 farklı Toping olsa bile, uygulama tüm bu somut pizza ve Topingler kombinasyonu koruyarak çıldırır.
İşte dekoratör deseni geliyor.
Dekoratör desenine göre, dekoratörleri uygulayacaksınız, çünkü dekoratörler ve pizzalar bu sosların dekoratörleri tarafından dekore edilecektir. Pratik olarak her müşteri arzusunun tepesini isteyecek ve nihai fatura tutarı temel pizzalardan oluşacak ve ayrıca sipariş edilen soslar olacaktır. Her tepesi dekoratörü, süslediği pizzaları ve fiyatını bilirdi. Topping nesnesinin GetPrice () yöntemi, hem pizzanın hem de tepenin kümülatif fiyatını döndürür.
Aşağıda, açıklamaya ilişkin bir kod örneği verilmiştir.
public abstract class BasePizza
{
protected double myPrice;
public virtual double GetPrice()
{
return this.myPrice;
}
}
public abstract class ToppingsDecorator : BasePizza
{
protected BasePizza pizza;
public ToppingsDecorator(BasePizza pizzaToDecorate)
{
this.pizza = pizzaToDecorate;
}
public override double GetPrice()
{
return (this.pizza.GetPrice() + this.myPrice);
}
}
class Program
{
[STAThread]
static void Main()
{
//Client-code
Margherita pizza = new Margherita();
Console.WriteLine("Plain Margherita: " + pizza.GetPrice().ToString());
ExtraCheeseTopping moreCheese = new ExtraCheeseTopping(pizza);
ExtraCheeseTopping someMoreCheese = new ExtraCheeseTopping(moreCheese);
Console.WriteLine("Plain Margherita with double extra cheese: " + someMoreCheese.GetPrice().ToString());
MushroomTopping moreMushroom = new MushroomTopping(someMoreCheese);
Console.WriteLine("Plain Margherita with double extra cheese with mushroom: " + moreMushroom.GetPrice().ToString());
JalapenoTopping moreJalapeno = new JalapenoTopping(moreMushroom);
Console.WriteLine("Plain Margherita with double extra cheese with mushroom with Jalapeno: " + moreJalapeno.GetPrice().ToString());
Console.ReadLine();
}
}
public class Margherita : BasePizza
{
public Margherita()
{
this.myPrice = 6.99;
}
}
public class Gourmet : BasePizza
{
public Gourmet()
{
this.myPrice = 7.49;
}
}
public class ExtraCheeseTopping : ToppingsDecorator
{
public ExtraCheeseTopping(BasePizza pizzaToDecorate)
: base(pizzaToDecorate)
{
this.myPrice = 0.99;
}
}
public class MushroomTopping : ToppingsDecorator
{
public MushroomTopping(BasePizza pizzaToDecorate)
: base(pizzaToDecorate)
{
this.myPrice = 1.49;
}
}
public class JalapenoTopping : ToppingsDecorator
{
public JalapenoTopping(BasePizza pizzaToDecorate)
: base(pizzaToDecorate)
{
this.myPrice = 1.49;
}
}
Bu, mevcut bir nesneye dinamik olarak yeni bir davranış veya Dekoratör kalıbı eklemenin basit bir örneğidir. Javascript gibi dinamik dillerin doğası gereği, bu model dilin kendisinin bir parçası haline gelir.
// Person object that we will be decorating with logging capability
var person = {
name: "Foo",
city: "Bar"
};
// Function that serves as a decorator and dynamically adds the log method to a given object
function MakeLoggable(object) {
object.log = function(property) {
console.log(this[property]);
}
}
// Person is given the dynamic responsibility here
MakeLoggable(person);
// Using the newly added functionality
person.log('name');
switch
ya da basit içinde if
, bunun bir sınıfa dinamik olarak davranış eklemenin harika bir örneği olduğunu iddia edebilirsiniz.Ancak, bu desende bir dekoratör ve süslü nesneler tanımlamak için en az iki sınıfa ihtiyacımız var.
Java i / o modelinin dekoratör desenine dayandığını belirtmek gerekir. Bu okuyucunun o okuyucunun üstüne katmanlanması, dekoratör için gerçekten gerçek bir dünya örneğidir.
Örnek - Senaryo- Diyelim ki bir şifreleme modülü yazıyorsunuz. Bu şifreleme, temiz dosyayı DES - Data şifreleme standardını kullanarak şifreleyebilir. Benzer şekilde, bir sistemde şifrelemeyi AES - Gelişmiş şifreleme standardı olarak alabilirsiniz. Ayrıca, şifreleme kombinasyonuna sahip olabilirsiniz - Önce DES, sonra AES. Veya önce AES sonra DES'e sahip olabilirsiniz.
Tartışma- Bu durumu nasıl karşılayacaksınız? Bu tür kombinasyonların nesnesini oluşturmaya devam edemezsiniz - örneğin - AES ve DES - toplam 4 kombinasyon. Bu nedenle, 4 ayrı nesneye sahip olmanız gerekir. Bu, şifreleme türü artacağından karmaşık hale gelecektir.
Çözüm - İhtiyaca göre yığın kombinasyonlarını çalışma zamanında oluşturmaya devam edin. Bu yığın yaklaşımının bir diğer avantajı, kolayca çözebilmenizdir.
İşte çözüm - C ++ ile.
İlk olarak, bir temel sınıfa ihtiyacınız var - yığının temel bir birimi. Yığının temeli olarak düşünebilirsiniz. Bu örnekte, açık dosyadır. Her zaman polimorfizmi takip edelim. İlk önce bu temel birimin arayüz sınıfını yapın. Bu şekilde, istediğiniz gibi uygulayabilirsiniz. Ayrıca, bu temel birimi dahil ederken bağımlılığı düşünmenize gerek yoktur.
İşte arayüz sınıfı -
class IclearData
{
public:
virtual std::string getData() = 0;
virtual ~IclearData() = 0;
};
IclearData::~IclearData()
{
std::cout<<"Destructor called of IclearData"<<std::endl;
}
Şimdi, bu arayüz sınıfını uygulayın -
class clearData:public IclearData
{
private:
std::string m_data;
clearData();
void setData(std::string data)
{
m_data = data;
}
public:
std::string getData()
{
return m_data;
}
clearData(std::string data)
{
setData(data);
}
~clearData()
{
std::cout<<"Destructor of clear Data Invoked"<<std::endl;
}
};
Şimdi, bir dekoratör soyut sınıfı yapalım - her türlü lezzet yaratmak için genişletilebilir - burada lezzet şifreleme türüdür. Bu dekoratör soyut sınıfı temel sınıfla ilgilidir. Böylece, dekoratör "bir tür" arayüz sınıfıdır. Bu nedenle, kalıtım kullanmanız gerekir.
class encryptionDecorator: public IclearData
{
protected:
IclearData *p_mclearData;
encryptionDecorator()
{
std::cout<<"Encryption Decorator Abstract class called"<<std::endl;
}
public:
std::string getData()
{
return p_mclearData->getData();
}
encryptionDecorator(IclearData *clearData)
{
p_mclearData = clearData;
}
virtual std::string showDecryptedData() = 0;
virtual ~encryptionDecorator() = 0;
};
encryptionDecorator::~encryptionDecorator()
{
std::cout<<"Encryption Decorator Destructor called"<<std::endl;
}
Şimdi somut bir dekoratör sınıfı yapalım - Şifreleme türü - AES -
const std::string aesEncrypt = "AES Encrypted ";
class aes: public encryptionDecorator
{
private:
std::string m_aesData;
aes();
public:
aes(IclearData *pClearData): m_aesData(aesEncrypt)
{
p_mclearData = pClearData;
m_aesData.append(p_mclearData->getData());
}
std::string getData()
{
return m_aesData;
}
std::string showDecryptedData(void)
{
m_aesData.erase(0,m_aesData.length());
return m_aesData;
}
};
Şimdi dekoratör türünün DES olduğunu varsayalım -
const std :: string desEncrypt = "DES Şifreli";
class des: public encryptionDecorator
{
private:
std::string m_desData;
des();
public:
des(IclearData *pClearData): m_desData(desEncrypt)
{
p_mclearData = pClearData;
m_desData.append(p_mclearData->getData());
}
std::string getData(void)
{
return m_desData;
}
std::string showDecryptedData(void)
{
m_desData.erase(0,desEncrypt.length());
return m_desData;
}
};
Bu dekoratör sınıfını kullanmak için bir istemci kodu yapalım -
int main()
{
IclearData *pData = new clearData("HELLO_CLEAR_DATA");
std::cout<<pData->getData()<<std::endl;
encryptionDecorator *pAesData = new aes(pData);
std::cout<<pAesData->getData()<<std::endl;
encryptionDecorator *pDesData = new des(pAesData);
std::cout<<pDesData->getData()<<std::endl;
/** unwind the decorator stack ***/
std::cout<<pDesData->showDecryptedData()<<std::endl;
delete pDesData;
delete pAesData;
delete pData;
return 0;
}
Aşağıdaki sonuçları göreceksiniz -
HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
DES Encrypted AES Encrypted HELLO_CLEAR_DATA
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Destructor called
Destructor called of IclearData
Encryption Decorator Destructor called
Destructor called of IclearData
Destructor of clear Data Invoked
Destructor called of IclearData
İşte UML diyagramı - Sınıf gösterimi. Durumda, kodu atlamak ve tasarım yönüne odaklanmak istersiniz.
strategy pattern
mi?
Dekoratör deseni, bu nesnenin diğer benzer alt sınıflarıyla zincir oluşturarak nesnenizin işlevselliğini değiştirmenize veya yapılandırmanıza yardımcı olur.
En iyi örnek, java.io paketindeki InputStream ve OutputStream sınıflarıdır
File file=new File("target","test.txt");
FileOutputStream fos=new FileOutputStream(file);
BufferedOutputStream bos=new BufferedOutputStream(fos);
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.write(5);
oos.writeBoolean(true);
oos.writeBytes("decorator pattern was here.");
//... then close the streams of course.
Java Dekoratör Tasarım Deseni Nedir.
GoF kitabındaki Dekoratör deseninin resmi tanımı (Tasarım Desenleri: Yeniden Kullanılabilir Nesneye Dayalı Yazılımın Öğeleri, 1995, Pearson Education, Inc. Pearson Addison Wesley olarak Yayıncılık) şunları yapabilir,
"Bir nesneye dinamik olarak ek sorumluluklar ekleyin. Dekoratörler, işlevselliği genişletmek için alt sınıflamaya esnek bir alternatif sunar."
Diyelim ki bir pizzamız var ve tavuk masala, soğan ve mozzarella peyniri gibi soslarla süslemek istiyoruz. Java ile nasıl uygulanacağını görelim ...
Java Dekoratör Tasarım Deseni nasıl uygulanacağını göstermek için program.
Pizza.java:
<!-- language-all: lang-html -->
package com.hubberspot.designpattern.structural.decorator;
public class Pizza {
public Pizza() {
}
public String description(){
return "Pizza";
}
}
package com.hubberspot.designpattern.structural.decorator;
public abstract class PizzaToppings extends Pizza {
public abstract String description();
}
package com.hubberspot.designpattern.structural.decorator;
public class ChickenMasala extends PizzaToppings {
private Pizza pizza;
public ChickenMasala(Pizza pizza) {
this.pizza = pizza;
}
@Override
public String description() {
return pizza.description() + " with chicken masala, ";
}
}
package com.hubberspot.designpattern.structural.decorator;
public class MozzarellaCheese extends PizzaToppings {
private Pizza pizza;
public MozzarellaCheese(Pizza pizza) {
this.pizza = pizza;
}
@Override
public String description() {
return pizza.description() + "and mozzarella cheese.";
}
}
package com.hubberspot.designpattern.structural.decorator;
public class Onion extends PizzaToppings {
private Pizza pizza;
public Onion(Pizza pizza) {
this.pizza = pizza;
}
@Override
public String description() {
return pizza.description() + "onions, ";
}
}
package com.hubberspot.designpattern.structural.decorator;
public class TestDecorator {
public static void main(String[] args) {
Pizza pizza = new Pizza();
pizza = new ChickenMasala(pizza);
pizza = new Onion(pizza);
pizza = new MozzarellaCheese(pizza);
System.out.println("You're getting " + pizza.description());
}
}
Dekoratör desenini işimde yoğun olarak kullandım. Blogumda günlüğe kaydetme ile nasıl kullanılacağı hakkında bir yazı yaptım .
Dekoratör deseni, nesnelere dinamik olarak davranış eklemenizi sağlar.
Farklı hamburger türlerinin fiyatını hesaplayan bir uygulama oluşturmanız gereken yere bir örnek alalım. Her biri temel hamburgere göre bir fiyatı olan "büyük" veya "peynirli" gibi farklı burger çeşitlerini kullanmanız gerekir. Örneğin peynirli burger için 10 $ ekleyin, büyük burger için ekstra 15 $ ekleyin, vb.
Bu durumda, bunları işlemek için alt sınıflar yaratmaya cazip gelebilirsiniz. Bunu Ruby'de şöyle ifade edebiliriz:
class Burger
def price
50
end
end
class BurgerWithCheese < Burger
def price
super + 15
end
end
Yukarıdaki örnekte, BurgerWithCheese sınıfı Burger'den miras alır ve süper sınıfta tanımlanan fiyata 15 $ eklemek için fiyat yöntemini geçersiz kılar. Ayrıca bir LargeBurger sınıfı oluşturacak ve Burger'e göre fiyatı tanımlayacaksınız. Ama aynı zamanda "büyük" ve "peynir" kombinasyonu için yeni bir sınıf tanımlamanız gerekiyor.
Şimdi "patates kızartması ile burger" servis etmemiz gerekiyorsa ne olur? Bu kombinasyonları ele almak için zaten 4 sınıfımız var ve "büyük", "peynirli" ve "patatesli" olmak üzere 3 özelliğin tüm kombinasyonunu işlemek için 4 tane daha eklememiz gerekecek. Şimdi 8 sınıfa ihtiyacımız var. Başka bir mülk ekleyin ve 16'ya ihtiyacımız olacak. Bu, 2 ^ n olarak büyüyecek.
Bunun yerine, bir Burger nesnesini alan bir BurgerDecorator tanımlamayı deneyelim:
class BurgerDecorator
def initialize(burger)
self.burger = burger
end
end
class BurgerWithCheese < BurgerDecorator
def price
self.burger.price + 15
end
end
burger = Burger.new
cheese_burger = BurgerWithCheese.new(burger)
cheese_burger.price # => 65
Yukarıdaki örnekte, BurgerWithCheese sınıfının miras aldığı bir BurgerDecorator sınıfı oluşturduk. Ayrıca LargeBurger sınıfı oluşturarak "büyük" varyasyonu temsil edebiliriz. Şimdi çalışma zamanında peynirli büyük bir hamburger şöyle tanımlayabiliriz:
b = LargeBurger.new(cheese_burger)
b.price # => 50 + 15 + 20 = 85
"Patates kızartması" varyasyonunu eklemek için kalıtımın nasıl 4 alt sınıf daha ekleneceğini hatırlıyor musunuz? Dekoratörler ile, yeni varyasyonu yönetmek ve bunu çalışma zamanında ele almak için sadece bir yeni sınıf, BurgerWithFries yaratacağız. Her yeni mülk, tüm permütasyonları karşılamak için sadece daha fazla dekoratöre ihtiyaç duyacaktır.
PS. Bu, daha ayrıntılı örnekler bulmak isterseniz okuyabileceğiniz Ruby'deki Dekoratör Desenini kullanma hakkında yazdığım bir makalenin kısa sürümüdür .
Dekoratör:
Kaynak yapımına bakın fazla ayrıntı makalesine .
Dekoratör (Özet) : Bileşen arabirimini uygulayan soyut bir sınıf / arabirimdir. Bileşen arabirimi içerir. Bu sınıfın yokluğunda, farklı kombinasyonlar için birçok ConcreteDecorator alt sınıfına ihtiyacınız vardır. Bileşenin bileşimi gereksiz alt sınıfları azaltır.
JDK örneği:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
while(bis.available()>0)
{
char c = (char)bis.read();
System.out.println("Char: "+c);;
}
UML diyagramı ve kod örnekleri için aşağıdaki SE sorusuna bir göz atın.
Yararlı makaleler:
Dekoratör deseninin gerçek kelime örneği: VendingMachineDecorator @
Dekoratör Kalıbı Ne Zaman Kullanılmalı?
Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();
beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();
Yukarıdaki örnekte, Çay veya Kahve (İçecek), Şeker ve Limon ile dekore edilmiştir.
Dekoratör deseni , herhangi bir nesneye dinamik olarak sorumluluk eklemek için tek bir hedefe ulaşır .
Java I / O Modeli dekoratör desenine dayanmaktadır.
Wikipedia'da bir pencereyi kaydırma çubuğuyla süslemeyle ilgili bir örnek var:
http://en.wikipedia.org/wiki/Decorator_pattern
İşte, dekoratör deseninin basit miras ile yeri doldurulamaz olduğunu gösteren "Takım üyesi, takım lideri ve menajeri" nin çok 'gerçek dünya' örneği:
https://zishanbilal.wordpress.com/2011/04/28/design-patterns-by-examples-decorator-pattern/
Bir süre önce Decorator kalıbı kullanarak bir kod temeli yeniden düzenlenmiş vardı, bu yüzden kullanım durumunu açıklamaya çalışacağım.
Bir dizi hizmetimiz olduğunu varsayalım ve kullanıcının belirli bir hizmet lisansı edip etmediğine bağlı olarak, hizmeti başlatmamız gerekir.
Tüm hizmetlerin ortak bir arayüzü var
interface Service {
String serviceId();
void init() throws Exception;
void start() throws Exception;
void stop() throws Exception;
}
abstract class ServiceSupport implements Service {
public ServiceSupport(String serviceId, LicenseManager licenseManager) {
// assign instance variables
}
@Override
public void init() throws Exception {
if (!licenseManager.isLicenseValid(serviceId)) {
throw new Exception("License not valid for service");
}
// Service initialization logic
}
}
Dikkatli bir şekilde gözlemlerseniz ServiceSupport
, bağımlıdır LicenseManager
. Peki neden bağımlı olmalı LicenseManager
? Lisans bilgilerini kontrol etmesine gerek olmayan arka plan hizmetine ihtiyacımız olsaydı. Mevcut durumda bir şekilde LicenseManager
geri dönmek için eğitim almamız gerekecektrue
arka plan hizmetleri üzere . Bu yaklaşım bana pek iyi gelmedi. Bana göre lisans kontrolü ve diğer mantık birbirine dikti.
Yani dekoratör Desen kurtarmaya gelir ve burada TDD ile üstlenmeden başlar.
class LicensedService implements Service {
private Service service;
public LicensedService(LicenseManager licenseManager, Service service) {
this.service = service;
}
@Override
public void init() {
if (!licenseManager.isLicenseValid(service.serviceId())) {
throw new Exception("License is invalid for service " + service.serviceId());
}
// Delegate init to decorated service
service.init();
}
// override other methods according to requirement
}
// Not concerned with licensing any more :)
abstract class ServiceSupport implements Service {
public ServiceSupport(String serviceId) {
// assign variables
}
@Override
public void init() {
// Service initialization logic
}
}
// The services which need license protection can be decorated with a Licensed service
Service aLicensedService = new LicensedService(new Service1("Service1"), licenseManager);
// Services which don't need license can be created without one and there is no need to pass license related information
Service aBackgroundService = new BackgroundService1("BG-1");
PubG örneğini ele alalım. Saldırı tüfekleri en iyi 4x zum ile çalışır ve biz üzerindeyken, kompansatör ve baskılayıcıya da ihtiyacımız olur. Geri tepmeyi ve yanma sesini ve yanma sesini azaltır. Oyuncuların en sevdikleri silahı ve aksesuarlarını satın almalarına izin vereceğimiz bu özelliği uygulamamız gerekecek. Oyuncular silahı veya aksesuarın bir kısmını veya aksesuarın tamamını satın alabilir ve buna göre şarj olurlar.
Dekoratör deseninin nasıl uygulandığını burada görelim:
Birisinin yukarıda bahsedilen üç aksesuarla birlikte SCAR-L satın almak istediğini varsayalım.
Bu, aşağıdaki gibi bir sınıf diyagramına yol açacaktır:
Şimdi, bunun gibi sınıflarımız olabilir:
public abstract class Gun {
private Double cost;
public Double getCost() {
return cost;
}
}
public abstract class GunAccessories extends Gun { }
public class Scarl extends Gun {
public Scarl() {
cost = 100;
}
}
public class Suppressor extends GunAccessories {
Gun gun;
public Suppressor(Gun gun) {
cost = 5;
this.gun = gun;
}
public double getCost(){
return cost + gun.getCost();
}
}
public class GunShop{
public static void main(String args[]){
Gun scarl = new Scarl();
scarl = new Supressor(scarl);
System.out.println("Price is "+scarl.getCost());
}
}
Benzer şekilde başka aksesuarlar da ekleyebilir ve Silahımızı dekore edebiliriz.
Referans:
https://nulpointerexception.com/2019/05/05/a-beginner-guide-to-decorator-pattern/
Dekoratör Tasarım Deseni : Bu desen, çalışma zamanında bir nesnenin özelliklerini değiştirmeye yardımcı olur. Bir nesneye farklı lezzetler sağlar ve bu lezzette hangi malzemeleri kullanmak istediğimizi seçme esnekliği sağlar.
Gerçek Hayat Örneği: Bir uçuşta ana kabin koltuğunuz olduğunu varsayalım. Artık koltukla birden fazla aktivite seçmenize izin veriliyor. Her tatlılığın kendi maliyeti vardır. Şimdi bir kullanıcı Wifi ve premium yiyecek seçerse, koltuk + wifi + premium yiyecek için ücretlendirilecektir.
Bu durumda dekoratör tasarım deseni gerçekten bize yardımcı olabilir. Dekoratör düzeni ve bir gerçek hayat örneğinin uygulanması hakkında daha fazla bilgi edinmek için yukarıdaki bağlantıyı ziyaret edin.