वास्तविक दुनिया उदाहरण के साथ "डेकोरेटर पैटर्न" को समझें


167

मैं GOF में प्रलेखित के रूप में डेकोरेटर पैटर्न का अध्ययन कर रहा था ।

कृपया, डेकोरेटर पैटर्न को समझने में मेरी मदद करें । क्या कोई उपयोग-मामले का उदाहरण दे सकता है कि यह वास्तविक दुनिया में कहां उपयोगी है?


8
आप यहाँ जावा API में कुछ
वास्तविक

एक लेख है कि शो सरल उदाहरण के साथ डेकोरेटर पैटर्न के लाभ: dzone.com/articles/is-inheritance-dead
nbilal

जवाबों:


226

डेकोरेटर पैटर्न गतिशील रूप से किसी भी वस्तु में जिम्मेदारियों को जोड़ने का एक उद्देश्य प्राप्त करता है।

पिज्जा की दुकान के एक मामले पर विचार करें। पिज्जा की दुकान में वे कुछ पिज्जा किस्में बेचेंगे और वे मेनू में टॉपिंग भी प्रदान करेंगे। अब एक ऐसी स्थिति की कल्पना करें जिसमें यदि पिज्जा शॉप को पिज्जा और टॉपिंग के प्रत्येक संयोजन के लिए मूल्य प्रदान करना है। यहां तक ​​कि अगर चार बुनियादी पिज्जा और 8 अलग टॉपिंग हैं, तो आवेदन पिज्जा और टॉपिंग के इन सभी ठोस संयोजन को बनाए रखने के लिए पागल हो जाएगा।

यहां डेकोरेटर पैटर्न आता है।

डेकोरेटर पैटर्न के अनुसार, आप सजावट के रूप में टॉपिंग को लागू करेंगे और पिज्जा को उन टॉपिंग्स के डेकोरेटर्स द्वारा सजाया जाएगा। व्यावहारिक रूप से प्रत्येक ग्राहक अपनी इच्छा की टॉपिंग चाहता है और अंतिम बिल-राशि आधार पिज्जा से बना होगा और इसके अलावा टॉपिंग का आदेश दिया जाएगा। प्रत्येक टॉपिंग डेकोरेटर को पिज्जा के बारे में पता होगा कि यह सज रहा है और इसकी कीमत है। GetPrice () टॉपिंग ऑब्जेक्ट का तरीका पिज्जा और टॉपिंग दोनों का संचयी मूल्य लौटाएगा।

संपादित करें

यहां ऊपर दिए गए स्पष्टीकरण का एक कोड-उदाहरण है।

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
इस पैटर्न को एक बिट पसंद नहीं है। शायद इसका उदाहरण है। OOD के संदर्भ में मेरे पास मुख्य मुद्दा यह है कि टॉपिंग पिज्जा नहीं है । पिज्जा की कीमत के लिए टॉपिंग से यह कहना कि यह मेरे साथ सही नहीं बैठता है। हालांकि यह एक बहुत ही विचारशील और विस्तृत उदाहरण है, इसलिए मेरा मतलब यह नहीं है कि आप इसके लिए दस्तक दें।
टॉम डब्ल्यू

39
@TomW मुझे लगता है कि इस मुद्दे का हिस्सा नामकरण है। सभी "टॉपिंग" वर्गों को "पिज़्ज़ाविथ <टॉपिंग>" कहा जाना चाहिए। उदाहरण के लिए, "पिज़्ज़ाविथ मशरूम"।
जोश नू

2
मेरी राय में, सज्जाकारों को यथासंभव सपाट रूप से उपयोग किया जाता है। मेरा मतलब है कि जितना संभव हो सके "डेकोरेटर्स रैपिंग डेकोरेटर्स"। तो शायद यह उदाहरण सबसे उपयुक्त नहीं है। लेकिन यह काफी गहन है, जो अच्छा है।
वेकिंगफ्रूट

17
दूसरे दृष्टिकोण से यह "वास्तविक दुनिया" के करीब भी नहीं है। वास्तविक दुनिया में आपको प्रत्येक बार मेनू में एक नया टॉपिंग जोड़ने की आवश्यकता नहीं है (या मूल्य को बदलना चाहिए)। टॉपिंग्स डेटाबेस में संग्रहीत (आमतौर पर) होते हैं और इस प्रकार उपरोक्त उदाहरण को बेकार कर देते हैं।
स्टेलियोस एडमांटिडिस

4
^ यह। मुझे लगता है कि इस पैटर्न का अध्ययन करते समय यह सब मुझे परेशान कर रहा है। अगर मैं एक सॉफ्टवेयर कंपनी होता और पिज्जा शॉप सॉफ्टवेयर लिखता, तो मैं हर बार रिजेक्ट और रिस्पेक्ट नहीं करना चाहता। मैं बैकएंड में एक तालिका में एक पंक्ति जोड़ना चाहता हूं या कुछ ऐसा जो आसानी से उनकी आवश्यकता का ध्यान रखेगा। अच्छी तरह से कहा, @Stelios Adamantidis। मुझे लगता है कि पैटर्न सबसे बड़ी ताकत है, हालांकि तब 3-पार्टी कक्षाओं को संशोधित करना होगा।
Canucklesandwich

33

यह एक मौजूदा वस्तु को गतिशील रूप से, या डेकोरेटर पैटर्न में नए व्यवहार को जोड़ने का एक सरल उदाहरण है। जावास्क्रिप्ट जैसी गतिशील भाषाओं की प्रकृति के कारण, यह पैटर्न भाषा का हिस्सा बन जाता है।

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


सरल और सटीक! महान उदाहरण!
नागेंद्र ५४ n

1
मुझे नहीं लगता कि डेकोरेटर पैटर्न की अवधारणा यहां लागू है। वास्तव में यह एक पैटर्न नहीं है! हां, आप रनटाइम में एक नई विधि जोड़ रहे हैं। और शायद एक switchया एक साधारण के अंदर if, आप यह दावा करने में सक्षम होंगे कि यह गतिशील रूप से कक्षा में व्यवहार को जोड़ने का एक बढ़िया उदाहरण है। लेकिन, हमें इस पैटर्न में डेकोरेटर और सजी हुई वस्तुओं को परिभाषित करने के लिए कम से कम दो वर्गों की आवश्यकता है।
इमान

1
@ मैं समझता हूं कि मेरे उदाहरण में कोई डेकोरेटर नहीं है, लेकिन यह एक डेकोरेटर के रूप में कार्य करने वाले फ़ंक्शन को जोड़कर आसानी से तय किया गया है। लेकिन मेरे उदाहरण में एक सजी हुई वस्तु है। क्या पैटर्न कहीं भी कहता है कि आपको विशेष रूप से दो वर्गों की आवश्यकता है ?
अनुराग

18

यह ध्यान देने योग्य है कि जावा i / o मॉडल डेकोरेटर पैटर्न पर आधारित है। इस पाठक के शीर्ष पर उस पाठक के शीर्ष पर लेयरिंग ... सज्जाकार का एक वास्तविक वास्तविक उदाहरण है।


क्या वास्तविक सार्वजनिक एपीआई में कोई अन्य उदाहरण हैं? यह केवल एक ही है जिसे मैं जानता हूं।
जोशियाह योडर

ऐसा लगता है कि प्रकृति में सभी आवरण कार्यों में किसी प्रकार के डेकोरेटर पैटर्न का निर्माण होता है, क्या मुझे लगता है कि यह है?
हार्वे लिन

अच्छा उदाहरण !!
नागेंद्र ५४ n

8

उदाहरण - परिदृश्य- मान लीजिए कि आप एक एन्क्रिप्शन मॉड्यूल लिख रहे हैं। यह एन्क्रिप्शन डेस - डेटा एन्क्रिप्शन मानक का उपयोग करके स्पष्ट फ़ाइल को एन्क्रिप्ट कर सकता है। इसी तरह, एक सिस्टम में आपके पास एन्क्रिप्शन एईएस के रूप में हो सकता है - एडवांस एन्क्रिप्शन मानक। इसके अलावा, आपके पास एन्क्रिप्शन का संयोजन हो सकता है - पहले डेस, फिर एईएस। या आपके पास पहले एईएस हो सकता है, फिर डीईएस।

चर्चा- आप इस स्थिति को कैसे पूरा करेंगे? आप ऐसे संयोजनों का उद्देश्य नहीं बना सकते हैं - उदाहरण के लिए - एईएस और डीईएस - कुल 4 संयोजन। इस प्रकार, आपको 4 अलग-अलग ऑब्जेक्ट्स की आवश्यकता है यह जटिल हो जाएगा क्योंकि एन्क्रिप्शन प्रकार बढ़ जाएगा।

समाधान - रन समय पर जरूरत के आधार पर स्टैक - संयोजन का निर्माण करते रहें। इस स्टैक दृष्टिकोण का एक और लाभ यह है कि आप इसे आसानी से खोल सकते हैं।

यहाँ समाधान है - C ++ में।

सबसे पहले, आपको आधार वर्ग की आवश्यकता है - स्टैक की एक मौलिक इकाई। आप स्टैक के आधार के रूप में सोच सकते हैं। इस उदाहरण में, यह स्पष्ट फ़ाइल है। चलो हमेशा बहुरूपता का पालन करें। इस मूलभूत इकाई का पहला इंटरफ़ेस वर्ग बनाएं। इस तरह, आप इसे अपनी इच्छानुसार कार्यान्वित कर सकते हैं। इसके अलावा, आपको इस मूलभूत इकाई को शामिल करते समय निर्भरता के बारे में सोचने की आवश्यकता नहीं है।

यहाँ इंटरफ़ेस वर्ग है -

class IclearData
{
public:

    virtual std::string getData() = 0;
    virtual ~IclearData() = 0;
};

IclearData::~IclearData()
{
    std::cout<<"Destructor called of IclearData"<<std::endl;
}

अब, इस इंटरफ़ेस वर्ग को लागू करें -

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

};

अब, चलो एक डेकोरेटर एब्स्ट्रैक्ट क्लास बनाते हैं - जिसे किसी भी प्रकार के स्वाद को बनाने के लिए बढ़ाया जा सकता है - यहाँ स्वाद एन्क्रिप्शन प्रकार है। यह डेकोरेटर एब्स्ट्रैक्ट क्लास बेस क्लास से संबंधित है। इस प्रकार, डेकोरेटर "एक प्रकार का इंटरफ़ेस क्लास है। इस प्रकार, आपको विरासत का उपयोग करने की आवश्यकता है।

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

अब, चलो एक ठोस डेकोरेटर वर्ग बनाते हैं - एन्क्रिप्शन प्रकार - एईएस -

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

};

अब, मान लें कि डेकोरेटर टाइप DES है -

const std :: string desEncrypt = "डेस एनक्रिप्टेड";

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

};

आइए इस डेकोरेटर वर्ग का उपयोग करने के लिए एक क्लाइंट कोड बनाते हैं -

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

आप निम्न परिणाम देखेंगे -

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

यहां यूएमएल आरेख है - इसका वर्ग प्रतिनिधित्व। मामले में, आप कोड को छोड़ना चाहते हैं और डिज़ाइन पहलू पर ध्यान केंद्रित करना चाहते हैं।

यहां छवि विवरण दर्ज करें


1
उदाहरण के लिए अधिक उपयुक्त नहीं है strategy pattern?
एक्सएक्सज़ियन

@exexzian हाँ, मेरे छात्र लगातार इस प्रकार की समस्या के लिए मुझे रणनीतियों की एक सूची सुझाते हैं, और यह मेरे लिए सबसे स्वच्छ समाधान की तरह महसूस करता है।
जोशिया योडर

नहीं, रणनीति पैटर्न के साथ आप एन्क्रिप्शन विधियों को संयोजित नहीं कर सकते। इसके लिए आपको हर संभव संयोजन के लिए एक रणनीति वर्ग बनाना होगा।
डीट्ज

4

डेकोरेटर पैटर्न आपको इस ऑब्जेक्ट के अन्य समान उपवर्गों के साथ पीछा करके अपनी वस्तु की कार्यक्षमता को बदलने या कॉन्फ़िगर करने में मदद करता है।

सबसे अच्छा उदाहरण java.io पैकेज में InputStream और OutputStream कक्षाएं होंगी

    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.

इस स्थिति में, कॉलिंग श्रृंखला ObjectOutputStream पर शुरू होती है, फिर फ़ाइल वर्ग तक सभी तरह से जाती है, फिर फ़ाइल वर्ग मान लौटाता है, फिर अन्य तीन उपवर्ग उन सभी को जोड़ते हैं और अंत में, ObjectOutputream की विधि इसे लौटा देती है, वह सही?
हार्वे लिन

3

जावा में डेकोरेटर डिज़ाइन पैटर्न क्या है।

GoF पुस्तक से डेकोरेटर पैटर्न की औपचारिक परिभाषा (डिजाइन पैटर्न: पुन: प्रयोज्य वस्तु-उन्मुख सॉफ्टवेयर के तत्व, 1995, पियर्सन एजुकेशन, इंक। पियर्सन एडिसन वेस्ले के रूप में प्रकाशन) का कहना है कि आप कर सकते हैं,

"गतिशील रूप से एक वस्तु के लिए अतिरिक्त जिम्मेदारियों को संलग्न करें। सज्जाकार कार्यक्षमता बढ़ाने के लिए उपवर्ग के लिए एक लचीला विकल्प प्रदान करते हैं।"

मान लीजिए कि हमारे पास एक पिज्जा है और हम इसे चिकन मसाला, प्याज और मोज़ेरेला चीज़ जैसे टॉपिंग से सजाना चाहते हैं। आइए देखें कि इसे जावा में कैसे लागू किया जाए ...

जावा में डेकोरेटर डिजाइन पैटर्न को लागू करने का तरीका प्रदर्शित करने के लिए कार्यक्रम।

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

मैंने अपने काम में बड़े पैमाने पर डेकोरेटर पैटर्न का उपयोग किया है। मैंने अपने ब्लॉग पर एक पोस्ट बनाई कि लॉगिंग के साथ इसका उपयोग कैसे करें।


मुझे यह पसंद नहीं है कि आपने केवल एक उत्तर के रूप में एक लिंक फेंक दिया। लेकिन आपका ब्लॉग लेख इतना मददगार है, कि मुझे बस उखाड़ना पड़ा :)। अब मैं वास्तव में इसे समझता हूं। हर कोई पिज्जा के साथ आ रहा है, और आप एक आदर्श उदाहरण के साथ।
निकलैस रबाब

2

डेकोरेटर पैटर्न आपको गतिशील रूप से वस्तुओं में व्यवहार जोड़ने देता है।

आइए एक उदाहरण लेते हैं जहां आपको एक ऐप बनाने की आवश्यकता होती है जो विभिन्न प्रकार के बर्गर की कीमत की गणना करता है। आपको बर्गर के विभिन्न रूपों को संभालने की आवश्यकता है, जैसे "बड़े" या "पनीर के साथ", जिनमें से प्रत्येक की कीमत मूल बर्गर के सापेक्ष है। जैसे पनीर के साथ बर्गर के लिए $ 10 जोड़ें, बड़े बर्गर के लिए अतिरिक्त $ 15 जोड़ें, आदि।

इस मामले में आपको इनको संभालने के लिए उपवर्ग बनाने का प्रलोभन दिया जा सकता है। हम रूबी में इसे व्यक्त कर सकते हैं:

class Burger
  def price
    50
  end
end

class BurgerWithCheese < Burger
  def price
    super + 15
  end
end

उपरोक्त उदाहरण में, बर्गरविथशेसी वर्ग बर्गर से विरासत में मिला है, और सुपर क्लास में परिभाषित मूल्य में $ 15 जोड़ने के लिए मूल्य पद्धति को ओवरराइड करता है। आप एक लार्जबर्गर क्लास भी बनाएंगे और बर्गर के सापेक्ष कीमत निर्धारित करेंगे। लेकिन आपको "बड़े" और "पनीर के साथ" के संयोजन के लिए एक नए वर्ग को परिभाषित करने की भी आवश्यकता है।

अब क्या होगा अगर हमें "बर्गर विद फ्राइज़" परोसना पड़े? हमारे पास उन संयोजनों को संभालने के लिए पहले से ही 4 कक्षाएं हैं, और हमें 3 गुणों के सभी संयोजन - "बड़े", "पनीर के साथ" और "फ्राइज़ के साथ" को संभालने के लिए 4 और जोड़ना होगा। हमें अभी 8 कक्षाएं चाहिए। एक और संपत्ति जोड़ें और हमें 16 की आवश्यकता होगी। यह 2 ^ n के रूप में बढ़ेगा।

इसके बजाय, आइए एक बर्गरडाइकोरेटर को परिभाषित करने का प्रयास करें जो बर्गर ऑब्जेक्ट में लेता है:

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

उपरोक्त उदाहरण में, हमने एक बर्गरडेकोरेटर वर्ग बनाया है, जिसमें से बर्गरविथेकस श्रेणी विरासत में मिली है। हम लार्जबर्गर क्लास बनाकर "बड़े" बदलाव का भी प्रतिनिधित्व कर सकते हैं। अब हम रनवे पर चीज़ के साथ एक बड़े बर्गर को परिभाषित कर सकते हैं:

b = LargeBurger.new(cheese_burger)
b.price  # => 50 + 15 + 20 = 85

याद रखें कि "फ्राइज़ के साथ" विविधता को जोड़ने के लिए विरासत का उपयोग करके 4 और उपवर्गों को कैसे जोड़ा जाएगा? डेकोरेटर्स के साथ, हम नए बदलाव को संभालने और रनटाइम के दौरान इसे संभालने के लिए सिर्फ एक नया वर्ग, बर्गरविथफ्रीज बनाएंगे। प्रत्येक नई संपत्ति को सभी क्रमपरिवर्तन को कवर करने के लिए बस अधिक डेकोरेटर की आवश्यकता होगी।

पुनश्च। यह एक लेख का छोटा संस्करण है जो मैंने रूबी में डेकोरेटर पैटर्न का उपयोग करने के बारे में लिखा था , जिसे आप पढ़ सकते हैं यदि आप अधिक विस्तृत उदाहरणों का पता लगाना चाहते हैं।


2

डेकोरेटर:

  1. रन टाइम में ऑब्जेक्ट में व्यवहार जोड़ें । इनहेरिटेंस इस कार्यक्षमता को प्राप्त करने की कुंजी है, जो इस पैटर्न का लाभ और नुकसान दोनों है।
  2. यह इंटरफ़ेस के व्यवहार को बढ़ाता है।
  3. डेकोरेटर को केवल एक घटक के साथ पतित कम्पोजिट के रूप में देखा जा सकता है । हालाँकि, एक डेकोरेटर अतिरिक्त ज़िम्मेदारियाँ जोड़ता है - यह ऑब्जेक्ट एकत्रीकरण के लिए अभिप्रेत नहीं है।
  4. डेकोरेटर वर्ग एलसीडी (सबसे निचले वर्ग के डेनिमिनेटर) इंटरफ़ेस के लिए एक संरचना संबंध की घोषणा करता है, और यह डेटा सदस्य इसके निर्माता में आरंभीकृत होता है।
  5. डेकोरेटर को सब-क्लासिंग के बिना ऑब्जेक्ट में जिम्मेदारियों को जोड़ने के लिए डिज़ाइन किया गया है

सोर्समेकिंग का संदर्भ लें अधिक जानकारी के लिए लेख।

डेकोरेटर (सार) : यह एक सार वर्ग / इंटरफ़ेस है, जो घटक इंटरफ़ेस को लागू करता है। इसमें घटक इंटरफ़ेस है। इस वर्ग की अनुपस्थिति में, आपको विभिन्न संयोजनों के लिए कंक्रीटकॉकरेटर के कई उप-वर्गों की आवश्यकता होती है। घटक की संरचना गैर-आवश्यक उप-वर्गों को कम करती है।

JDK उदाहरण:

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 आरेख और कोड उदाहरण के लिए SE प्रश्न के नीचे एक नज़र डालें।

IO के लिए डेकोरेटर पैटर्न

उपयोगी लेख:

journaldev

विकिपीडिया

डेकोरेटर पैटर्न का वास्तविक शब्द उदाहरण: VendingMachineDecorator @ समझाया गया है

डेकोरेटर पैटर्न का उपयोग कब करें?

Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();

beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();

उपरोक्त उदाहरण में, चीनी या नींबू द्वारा चाय या कॉफी (पेय) को सजाया गया है।


2

डेकोरेटर पैटर्न गतिशील रूप से किसी भी वस्तु में जिम्मेदारियों को जोड़ने का एक उद्देश्य प्राप्त करता है ।

जावा I / O मॉडल डेकोरेटर पैटर्न पर आधारित है।

डेकोरेटर पैटर्न के रूप में जावा आईओ


1

स्क्रॉलबार के साथ एक विंडो सजाने के बारे में विकिपीडिया पर एक उदाहरण है:

http://en.wikipedia.org/wiki/Decorator_pattern

यहाँ "टीम मेंबर, टीम लीड और मैनेजर" का एक और बहुत 'वास्तविक संसार' उदाहरण है, जो बताता है कि डेकोरेटर पैटर्न सरल विरासत के साथ अप्रतिरोध्य है:

https://zishanbilal.wordpress.com/2011/04/28/design-patterns-by-examples-decorator-pattern/


वह ज़िशान बिलाल लिंक महान है - सबसे अच्छा उदाहरण मैंने देखा है
स्टोंडॉउग

1

कुछ समय पहले मैंने डेकोरेटर पैटर्न का उपयोग करने के लिए एक कोडबेस को रिफलेक्ट किया था, इसलिए मैं उपयोग के मामले को समझाने की कोशिश करूंगा।

मान लें कि हमारे पास सेवाओं का एक सेट है और इस आधार पर कि उपयोगकर्ता ने विशेष सेवा का लाइसेंस प्राप्त किया है, हमें सेवा शुरू करने की आवश्यकता है।

सभी सेवाओं में एक सामान्य इंटरफ़ेस है

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

यदि आप ध्यान से देखते हैं, ServiceSupportपर निर्भर है LicenseManager। लेकिन यह निर्भर क्यों होना चाहिए LicenseManager? क्या होगा अगर हमें पृष्ठभूमि सेवा की आवश्यकता है जो लाइसेंस जानकारी की जांच करने की आवश्यकता नहीं है। वर्तमान स्थिति में हमें किसी तरह LicenseManagerवापस लौटने के लिए प्रशिक्षित करना होगाtrue पृष्ठभूमि सेवाओं के लिए । यह दृष्टिकोण मुझे ठीक नहीं लगा। मेरे अनुसार लाइसेंस जाँच और अन्य तर्क एक दूसरे के लिए रूढ़िवादी थे।

तो डेकोरेटर पैटर्न बचाव के लिए आता है और यहां टीडीडी के साथ रिफैक्टिंग शुरू होती है।

पोस्ट रिफैक्टरिंग

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

टेकअवे

  • कोड का सामंजस्य बेहतर हुआ
  • सेवा परीक्षण आसान हो गया, क्योंकि ServiceSupport का परीक्षण करते समय लाइसेंस का मजाक नहीं उड़ाना चाहिए
  • पृष्ठभूमि सेवाओं के लिए किसी विशेष चेक द्वारा लाइसेंस को बायपास करने की आवश्यकता नहीं है
  • जिम्मेदारियों का उचित विभाजन

1

PUBG का उदाहरण लेते हैं। असाल्ट राइफ़ल 4x ज़ूम के साथ सबसे अच्छा काम करती है और जब हम इस पर होते हैं, तो हमें कम्पेसाटर और दबानेवाला यंत्र की भी आवश्यकता होगी। यह पुनरावृत्ति को कम करेगा और फायरिंग ध्वनि के साथ-साथ गूंज को कम करेगा। हमें इस सुविधा को लागू करने की आवश्यकता होगी जहां हम खिलाड़ियों को उनकी पसंदीदा बंदूक और उनके सामान खरीदने की अनुमति देंगे। खिलाड़ी बंदूक या कुछ गौण या सभी गौण खरीद सकते हैं और उनके अनुसार शुल्क लिया जाएगा।

आइए देखें कि डेकोरेटर पैटर्न यहां कैसे लागू किया जाता है:

मान लीजिए कि कोई व्यक्ति उपरोक्त सभी तीन सामानों के साथ SCAR-L खरीदना चाहता है।

  1. SCAR-L की एक वस्तु लें
  2. 4x ज़ूम ऑब्जेक्ट के साथ SCAR-L को सजाने (या जोड़ें)
  3. SCAR-L को शमन वस्तु से सजाएँ
  4. SCAR-L को कंप्रेसर ऑब्जेक्ट से सजाएं
  5. लागत विधि को कॉल करें और प्रत्येक ऑब्जेक्ट को सामान की लागत विधि का उपयोग करके लागत पर जोड़ने दें

यह इस तरह एक वर्ग आरेख को जन्म देगा:

काम पर सज्जाकार पैटर्न

अब, हमारे पास इस तरह की कक्षाएं हो सकती हैं:

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

हम इसी तरह अन्य सामान भी जोड़ सकते हैं और अपने गन को सजा सकते हैं।

संदर्भ:

https://nulpointerexception.com/2019/05/05/a-beginner-guide-to-decorator-pattern/


0

डेकोरेटर डिज़ाइन पैटर्न : यह पैटर्न रनटाइम पर किसी ऑब्जेक्ट की विशेषताओं को संशोधित करने में मदद करता है। यह किसी वस्तु को अलग-अलग स्वाद प्रदान करता है और यह चुनने के लिए लचीलापन देता है कि हम उस स्वाद में किन सामग्रियों का उपयोग करना चाहते हैं।

वास्तविक जीवन उदाहरण: आओ हम कहते हैं कि आपके पास एक उड़ान में एक मुख्य केबिन सीट है। अब आपको सीट के साथ कई सुविधाएं चुनने की अनुमति है। प्रत्येक एमेनिटी की अपनी लागत होती है। अब यदि कोई उपयोगकर्ता वाईफ़ाई और प्रीमियम भोजन चुनता है, तो उसे सीट + वाईफाई + प्रीमियम भोजन के लिए शुल्क लिया जाएगा।

यहां छवि विवरण दर्ज करें

इस मामले में डेकोरेटर डिजाइन पैटर्न वास्तव में हमारी मदद कर सकता है। डेकोरेटर पैटर्न और एक वास्तविक जीवन उदाहरण के कार्यान्वयन के बारे में अधिक समझने के लिए उपरोक्त लिंक पर जाएं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.