पुस्तकालय पृथक्करण की अनुमति देते समय बहुरूपी व्यवहार के लिए डिजाइन पैटर्न


10

मान लीजिए कि मेरे पास Itemकक्षाओं का एक पदानुक्रम है Rectangle, Circle, Triangle:। मैं उन्हें आकर्षित करने में सक्षम होना चाहता हूं, इसलिए मेरी पहली संभावना Draw()प्रत्येक के लिए एक आभासी विधि जोड़ना है :

class Item {
public:
   virtual ~Item();
   virtual void Draw() =0; 
};

हालांकि, मैं ड्राइंग कार्यक्षमता को एक अलग ड्रॉ लाइब्रेरी में विभाजित करना चाहता हूं, जबकि कोर लाइब्रेरी में केवल मूल प्रतिनिधित्व शामिल हैं। संभावनाओं का एक जोड़ा है जिसके बारे में मैं सोच सकता हूं:

1 - एक है DrawManagerकि Itemएस की एक सूची लेता है और dynamic_cast<>काम करने के लिए उपयोग करने के लिए क्या करना है:

class DrawManager {
  void draw(ItemList& items) {
    FOREACH(Item* item, items) {
       if (dynamic_cast<Rectangle*>(item)) {
          drawRectangle();
       } else if (dynamic_cast<Circle*>(item)) {
          drawCircle();
       } ....
    }
  }
};

यह आदर्श नहीं है क्योंकि यह RTTI पर निर्भर करता है और एक वर्ग को पदानुक्रम में सभी वस्तुओं के बारे में जागरूक करने के लिए मजबूर करता है।

2 - अन्य दृष्टिकोण एक ItemDrawerपदानुक्रम ( RectangleDrawer, आदि) के लिए आरेखण जिम्मेदारी को स्थगित करना है :

class Item {
   virtual Drawer* GetDrawer() =0;
}

class Rectangle : public Item {
public:
   virtual Drawer* GetDrawer() {return new RectangleDrawer(this); }
}

यह वस्तुओं के आधार प्रतिनिधित्व और ड्राइंग के लिए कोड के बीच चिंताओं के अलगाव को प्राप्त करता है। हालांकि समस्या यह है कि आइटम वर्ग ड्राइंग कक्षाओं पर निर्भर हैं।

मैं इस ड्राइंग कोड को अलग लाइब्रेरी में कैसे अलग कर सकता हूं? क्या वस्तुओं का समाधान कुछ विवरण के कारखाने वर्ग को वापस करने के लिए है? हालाँकि, इसे कैसे परिभाषित किया जा सकता है ताकि कोर लाइब्रेरी ड्रॉ लाइब्रेरी पर निर्भर न हो?

जवाबों:


3

आगंतुक पैटर्न पर एक नज़र डालें ।

इसका उद्देश्य एक एल्गोरिथ्म (आपके मामले में ड्राइंग) को एक ऑब्जेक्ट संरचना से अलग करना है, जिस पर यह संचालित होता है (आइटम)।

तो आपकी समस्या के लिए एक सरल उदाहरण होगा:

class Item
{
public:
    virtual void visit(Visitable v)
    {
        v.accept(*this)
    }
};

class Rectangle : public Item
{
public:
    virtual void visit(Visitable v)
    {
        v.accept(*this)
    }
};

class Circle : public Item
{
public:
    virtual void visit(Visitable v)
    {
        v.accept(*this)
    }
};


class Visitable
{
public:
    virtual void accept(Rectangle& r);
    virtual void accept(Circle& c);
};

class Drawer : public Visitable
{
public:
    void accept(Rectangle& r)
    {
        // draw rectangle
    }   
    void accept(Circle& c)
    {
        // draw circle
    }
};


int main()
{
    Item* i1 = new Circle;
    Item* i2 = new Rectangle;

    Drawer d;
    i1->visit(d); // Draw circle
    i2->visit(d); // Draw rectangle

    return 1;
}

दिलचस्प - मैंने कभी भी बहुरूपता को प्राप्त करने के लिए एक आगंतुक का उपयोग करने के बारे में नहीं सोचा था। क्या यह रनटाइम के दौरान सही ढंग से ओवरलोड होगा?
The_mandrill

हाँ यह सही ढंग से अधिभार होगा। संपादित उत्तर देखें
हॉटपॉटो

मैं देख सकता हूं कि यह काम करता है। हालांकि यह शर्म की बात है कि प्रत्येक व्युत्पन्न वर्ग को visit()विधि को लागू करना होगा ।
the_mandrill

इसने मुझे थोड़ा और खोज करने के लिए प्रेरित किया और मैंने अब लोकी के विज़िटर पैटर्न के कार्यान्वयन को ढूंढ लिया है जो मुझे वही लग रहा है जिसकी मुझे तलाश है! मैं पेड़ों में नोड्स पर जाने के संदर्भ में विज़िटर पैटर्न से परिचित था, लेकिन अधिक सार तरीके से नहीं सोचा था।
The_mandrill

2

विभाजित आप दो समानांतर पदानुक्रमों में वर्णन करते हैं - अनिवार्य रूप से पुल पैटर्न है

आप चिंता करते हैं कि यह परिष्कृत अमूर्त (आयत आदि) को क्रियान्वयन (RectangleDrawer) पर निर्भर करता है , लेकिन मुझे यकीन नहीं है कि आप इससे पूरी तरह कैसे बच सकते हैं।

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

यह पूछने योग्य भी है कि क्या यह एक उपयोगी अमूर्त है। क्या एक आयत को खींचना इतना कठिन है कि यह एक अलग वर्ग में डालने लायक है, या क्या आप वास्तव में ग्राफिक्स लाइब्रेरी को अमूर्त करने की कोशिश कर रहे हैं?


मैंने सोचा था कि मैंने उस पैटर्न को समानांतर पदानुक्रम होने से पहले देखा था - उस पर मेरे दिमाग को जॉगिंग करने के लिए धन्यवाद। मैं हालांकि ग्राफिक्स लाइब्रेरी को अमूर्त करना चाहता हूं। मैं नहीं चाहता कि कोर लाइब्रेरी को ग्राफिक्स लाइब्रेरी पर निर्भर रहना पड़े। मान लीजिए कि मुख्य एप्लिकेशन आकार की वस्तुओं का प्रबंधन करता है और उन्हें प्रदर्शित करने के लिए पुस्तकालय एक ऐड-ऑन है। यह ध्यान में रखते हुए कि यह वास्तव में आयतों को आकर्षित करने के लिए एक आवेदन नहीं है - मैं इसे केवल एक रूपक के रूप में उपयोग कर रहा हूँ।
The_mandrill

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

1

मूल्य शब्दार्थ और अवधारणाओं पर आधारित बहुरूपता पर एक नजर है ।

यह काम बदल गया है कि मैं बहुरूपता को कैसे देखता हूं। हमने इस प्रणाली का उपयोग बार-बार की स्थितियों में बहुत प्रभावित करने के लिए किया है।


यह आकर्षक लग रहा है - ऐसा लगता है कि यह उस दिशा में जा रहा है जो मैं चाहता हूं
The_mandrill

1
लिंक टूट गया है। यही कारण है कि उत्तर जो अनिवार्य रूप से लिंक-केवल हतोत्साहित हैं।
अंजब

0

आपको समस्या क्यों हो रही है इसका कारण यह है कि वस्तुओं को खुद को आकर्षित नहीं करना चाहिए। किसी चीज़ को सही ढंग से खींचना एक अरब टुकड़ों पर निर्भर करता है और एक आयत में उन टुकड़ों में से कुछ भी नहीं होने वाला है। आपके पास एक केंद्रीय ग्राफ़िकल ऑब्जेक्ट होना चाहिए जो कि बैकबफ़र / डेप्थ बफर / शेड्स / आदि जैसी मुख्य स्थिति का प्रतिनिधित्व करता है, और फिर इसे ड्रा () विधि प्रदान करता है।


मैं मानता हूं कि वस्तुओं को खुद को आकर्षित नहीं करना चाहिए, इसलिए चिंताओं को अलग करने के लिए एक अलग वर्ग में उस क्षमता को स्थानांतरित करने की इच्छा। मान लीजिए कि ये वर्ग थे Dogया Cat- इन्हें खींचने के लिए जिम्मेदार वस्तु एक आयत बनाने की तुलना में बहुत अधिक जटिल है।
the_mandrill
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.