“Dekoratör Desenini” gerçek bir dünya örneğiyle anlayın


Yanıtlar:


226

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.

DÜZENLE

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;
    }
}

104
Bu kalıbı bir bit sevme. Belki de örnek. OOD açısından onunla ilgili ana sorun bir tepesi bir pizza değil olmasıdır . Uygulandığı pizzanın tepesini istemek sadece benimle oturmuyor. Yine de çok düşünceli ve ayrıntılı bir örnek, bu yüzden sizi bunun için çalmak istemiyorum.
Tom W

39
@TomW Sorunun bir kısmının adlandırma olduğunu düşünüyorum. Tüm "Topping" sınıfları "PizzaWith <Topping>" olarak adlandırılmalıdır. Örneğin, "PizzaWithMushrooms".
Josh Noe

2
Bence, dekoratörler en iyi şekilde mümkün olduğunca düz bir şekilde kullanılır. Bununla mümkün olduğunca küçük "dekoratörler sarmak dekoratörler" demek istiyorum. Belki de bu örnek en uygun olanı değildir. Ama oldukça kapsamlı, güzel.
thekingoftruth

17
Başka bir açıdan bakıldığında, bu "gerçek dünyaya" bile yakın değildir. Gerçek dünyada, menüde yeni bir eklenti eklemeniz (veya fiyatı değiştirmeniz) gerektiğinde yeniden derlememelisiniz. Topingler (genellikle) veritabanında saklanır ve bu nedenle yukarıdaki örneği işe yaramaz hale getirir.
Stelios Adamantidis

4
^ Bu. Bence bu model üzerinde çalışırken beni rahatsız eden şey bu. Bir yazılım şirketi olsaydım ve pizza dükkanı yazılımı yazsaydım, her seferinde yeniden derlemek ve yeniden göndermek zorunda kalmazdım. Arka uçtaki bir tabloya veya kolayca gereksinimlerini karşılayacak bir şey eklemek istiyorum. Güzel, @Stelios Adamantidis. Bence en büyük güç, o zaman üçüncü taraf sınıflarını değiştirmek olabilir.
Canucklesandwich

33

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');


Basit ve hassas! Harika bir örnek!
nagendra547

1
Dekoratör Kalıbı kavramının burada geçerli olduğunu düşünmüyorum. Aslında hiç bir desen değil !. Evet, çalışma zamanında yeni bir yöntem ekliyorsunuz. Ve muhtemelen bir switchya 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.
Iman

1
@Zich Örneğimde dekoratör olmadığını anlıyorum, ancak dekoratör olarak işlev gören bir işlev ekleyerek kolayca düzeltildi. Ama benim örneğimde süslü bir nesne var. Desen, özellikle iki sınıfa ihtiyacınız olan herhangi bir yerde mi söylüyor ?
Anurag

18

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.


Gerçek herkese açık API'larda başka örnekler var mı? Tek bildiğim bu.
Josiah Yoder

Görünüşe göre doğada tüm sarmalayıcı fonksiyonlarının bir çeşit dekoratör deseni var, sanırım öyle mi?
Harvey Lin

İyi örnek !!
nagendra547

8

Ö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.

resim açıklamasını buraya girin


1
örnek daha uygun değil strategy patternmi?
exexzian

@exexzian Evet, öğrencilerim sürekli olarak bu tür bir sorun için bana bir strateji listesi öneriyor ve bu benim için de en temiz çözüm gibi geliyor.
Josiah Yoder

Hayır, strateji modeliyle şifreleme yöntemlerini birleştiremezsiniz. Bu nedenle, olası her kombinasyon için bir strateji sınıfı oluşturmanız gerekir.
deetz

4

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.

Bu durumda, çağıran zincir ObjectOutputStream'de başlar, daha sonra File sınıfına kadar gider, sonra File sınıfı değeri döndürür, ardından diğer üç alt sınıf hepsini toplar ve son olarak ObjectOutputStream yönteminin değeri onu döndürür, bu doğru?
Harvey Lin

3

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());

}

}

3

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 .


Yanıt olarak sadece bir bağlantı attığınızı sevmiyorum. Ama Blog makaleniz, çok yararlı, ben sadece upvote :) gerekiyordu. Şimdi gerçekten anlıyorum. Herkes pizza ile geliyor ve siz de mükemmel bir örnekle.
Niklas Raab

2

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 .


2

Dekoratör:

  1. Çalışma zamanında nesneye davranış ekleyin . Kalıtım, bu modelin hem avantajı hem de dezavantajı olan bu işlevselliğe ulaşmanın anahtarıdır.
  2. Arayüz davranışını geliştirir .
  3. Dekoratör, sadece bir bileşenli dejenere bir Kompozit olarak görülebilir . Bununla birlikte, bir Dekoratör ek sorumluluklar ekler - nesne toplama için tasarlanmamıştır.
  4. Decorator sınıfı, LCD (En Düşük Sınıf Payda) arabirimiyle bir kompozisyon ilişkisi bildirir ve bu veri üyesi yapıcısında başlatılır.
  5. Dekoratör, alt sınıflandırma olmadan nesnelere sorumluluk eklemenize izin vermek için tasarlanmıştı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.

ES için Dekoratör Kalıbı

Yararlı makaleler:

journaldev

wikipedia

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.


2

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.

Dekoratör deseni olarak Java IO



1

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;
}

Ön Yeniden Düzenleme

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 LicenseManagergeri 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.

Yeniden Düzenleme Sonrası

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");

çıkarımlar

  • Kodun uyumu iyileşti
  • ServiceSupport'u test ederken lisanslamayı taklit etmek zorunda olmadığından birim testi daha kolay
  • Arka plan hizmetleri için özel denetimlerle lisanslamayı atlamanız gerekmez
  • Sorumlulukların uygun şekilde bölünmesi

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.

  1. SCAR-L nesnesini alın
  2. SCAR-L'yi 4x zoom nesnesiyle süsleyin (veya ekleyin)
  3. SCAR-L'yi baskılayıcı nesne ile süsleyin
  4. SCAR-L'yi kompresör nesnesiyle süsleyin
  5. Maliyet yöntemini çağırın ve her nesnenin aksesuarların maliyet yöntemini kullanarak maliyet eklemesine izin verin

Bu, aşağıdaki gibi bir sınıf diyagramına yol açacaktır:

Dekoratör desen iş başında

Ş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/


0

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.

resim açıklamasını buraya girin

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.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.