2010-08-03 12 views
6

यह मेरे अन्य प्रश्नों में से एक जैसा है, लेकिन मुझे लगता है कि एक नया सवाल वारंट करने के लिए काफी अलग है।अमूर्त कारखानों और इंजेक्शन के बारे में प्रश्न

मूल रूप से मैं एक उपयोगकर्ता इंटरफ़ेस लिख रहा हूं, और मेरे उपयोगकर्ता इंटरफ़ेस में नोड्स हैं जिन्हें चुना जा सकता है। जब कोई नोड चुना जाता है, तो उपयोगकर्ता इंटरफ़ेस एक अमूर्त नोड बेस क्लास "इनोड" के साथ समाप्त होता है। इससे मुझे नोड-> getFactory() करके एक कारखाना मिलता है, और इससे मैं उस नोड के लिए एप्राइपिएट डायलॉग या विचार बना सकता हूं क्योंकि सही कारखाना कंक्रीट नोड (जैसे फैक्ट्री-> createAddDialog(), फैक्ट्री- > createView (नोड), आदि)।

मेरा प्रश्न उस कारखाने के लिए पहली जगह नोड में जाने का सबसे अच्छा तरीका खोजने का प्रयास करने के बारे में है।

अब तक मैं 3 तरीके के बारे में सोचा गया है:

1) सही कारखाना सम्मिलित करें जब मैं नोड बनाने के लिए:

AreaNode *node = new AreaNode(new AreaNodeFactory()); 

तो AreaNode की परिभाषा है:

AreaNode : public INode 
{ 
    AreaNode(INodeAbstractFactory *injectedFactory) 
    { 
     m_injectedFactory = injectedFactory; 
    } 

    INodeAbstractFactory* getFactory() 
    { 
     return m_injectedFactory; 
    } 

    INodeAbstractFactory* m_injectedFactory; 
}; 

2) एक और सामान्य फैक्ट्री इंजेक्ट करें और नोड को उस कारखाने से फैक्ट्री प्राप्त करने दें:

AreaNode : public INode 
{ 
    AreaNode(IFactory *injectedFactory) 
    { 
     m_injectedFactory = injectedFactory; 
    } 

    INodeAbstractFactory* getFactory() 
    { 
     return m_injectedFactory->getAreaNodeFactory(); 
    } 

    IFactory* m_injectedFactory; 
} 

3) बस ठोस कारखाना बनाने (हालांकि यह बाद में परिवर्तन शायद के परीक्षण के लिए एक ही नोड के लिए विभिन्न कारखानों प्रयोग करने के लिए या के लिए गुंजाइश) निकालता है:

AreaNode : public INode 
{ 
    INodeAbstractFactory* getFactory() 
    { 
     return new AreaNodeFactory(); 
    } 
} 

वर्तमान विचारों को इन विकल्पों पर:

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

विकल्प 2: नोड को अमूर्त फैक्ट्री कार्यान्वयन के बारे में जानने के लिए मजबूर करता है जो getAreaNodeFactory को कॉल करने में सक्षम होने के लिए पर्याप्त है, जो ऐसी बुरी चीज नहीं हो सकती है। यह कम से कम यह सुनिश्चित करने में मदद करता है कि सही/एक ही कारखाना हमेशा लाया जाएगा (माना जाता है कि अधिक सामान्य कारखाना ठीक से लागू किया गया है)।

विकल्प 3: यह थोड़ा सीमित है क्योंकि मैं कक्षा को स्वैप करने में सक्षम नहीं हूं, और मैं कारखाने के ठोस कार्यान्वयन के बारे में जानने के लिए नोड पर उत्सुक नहीं हूं - हालांकि इस मामले में यह हो सकता है एक मुद्दा बहुत अधिक नहीं है (प्रसिद्ध अंतिम शब्द!)।

इस पर कोई विचार?

धन्यवाद।

संपादित करें: क्षमा करें मूल पोस्ट में परिवर्तनीय घोषणाओं को याद किया गया है, ठीक किया गया है।

संपादित करें: विकल्प 2 के साथ एक और समस्या है कि मुझे प्रत्येक नोड प्रकार में "getFactory" लागू करना है। कम से कम विकल्प 1 के साथ बेस क्लास हर बार इंजेक्ट अमूर्त कारखाना वर्ग वापस कर सकता है ..

+0

मैं भी यकीन है कि नोड्स कारखानों का उल्लेख होना चाहिए नहीं कर रहा हूँ। यूजर इंटरफेस को एक अमूर्त फैक्ट्री का संदर्भ देना चाहिए, और इसे बनाने के तरीकों में पारित नोड के प्रकार के आधार पर सही कंक्रीट फैक्ट्री का उपयोग सुनिश्चित करने के लिए पॉलीमोर्फिज्म का उपयोग करना चाहिए। इसके अलावा मुझे लगता है कि विकल्प 1 ठीक दिखता है। लेकिन मुझे विश्वास है कि नोड्स को किसी भी कारखानों के संदर्भ के बारे में पता नहीं होना चाहिए या नहीं। – Kurt

+0

@ कर्ट: डबल प्रेषण की अनुपस्थिति में, और प्रत्येक उपयोगकर्ता इंटरफ़ेस "एक्शन" के लिए विज़िटर क्लास के उपयोग से परहेज करते हुए मैं नोड के प्रकार के आधार पर नोड पर प्रदर्शन करना चाहता हूं, बेहतर समाधान क्या हो सकता है? एक नोड पर जो क्रिया मैं करना चाहता हूं वह इस प्रकार है: createAddDialog (parentWidget), createView (parentWidget), createMiniView (parentWidget), आदि। मैं केवल कंक्रीट नोड कक्षाओं, यानी क्षेत्र नोड के अंदर विधियों को रख सकता हूं -> createView (पैरेंट) - लेकिन यह अलगाव के लिए बहुत कुछ नहीं करता है। – Mark

+0

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

उत्तर

2

कैसे

के बारे में
class FactoryBase { /* interface */ } 
template <typename NodeType> class Factory : public FactoryBase { 
    // Default implementation. 
} 
// Add appropriate specializations for all relevant nodetypes, if needed. 
template <typename NodeType> inline Factory<NodeType> getFactory(NodeType*) { 
    return Factory<NodeType>(); 
} 

class AreaNode : public Node { 
    FactoryBase getFactory() { return getFactory(this); } 
}; 

खाका तर्क कटौती सुनिश्चित करेंगे कि कारखाने प्रकार this से ली गई है। इससे मैन्युअल गलतियों को रोकना चाहिए। लेकिन आम तौर पर, मैं सार्वजनिक रूप से कारखाने को उजागर करने से परेशान नहीं होता। बस आधार वर्ग के लिए निम्न बिट्स जोड़ें:

class Node { 
public: 
    std::Auto_ptr<View> createView() { 
    this->getFactory()->createView(this); 
    } // etc. 
private: 
    virtual FactoryBase* getFactory() = 0; 
}; 
+0

मैं नोड्स को ऐसी विधियों से रखने की कोशिश कर रहा था - यह नोड्स के लिए "createView" जैसी विधियों के बारे में "जानना" थोड़ा गलत लग रहा था, लेकिन शायद मैं गलत हूं। – Mark

+0

व्यक्तिगत नोड प्रकार नहीं होंगे। वे सिर्फ कारखानों का संदर्भ देते हैं। एपीआई विवरण बेस क्लास तक ही सीमित हैं, और वहां कारखाने के तरीकों को 'इस' को पारित करने के लिए मौजूद है। – MSalters

+0

ठीक है, मैं देखता हूं कि आपका क्या मतलब है - दूसरी तरफ कुर्ट की टिप्पणी है कि नोड्स को किसी भी कारखानों का संदर्भ नहीं होना चाहिए - तो फिर मैं फाड़ा हूं। प्रारंभ में मैंने आगंतुकों को डबल प्रेषण करने के लिए उपयोग किया, लेकिन यह हर कार्रवाई के लिए उनका उपयोग करने के लिए बहुत बोझिल हो गया, और नोड के प्रकारों की वजह से वे बहुत बड़े हो गए। – Mark

2

कैसे।

template<typename Factory> 
class AreaNode : public INode 
{ 
public: 
     virtual ~AreaNode(){} 

     AreaNode() : pFactory_(new Factory()) 
     {   
     } 

     const shared_ptr<IFactory>& GetFactory() 
     { 
      return pFactory_; 
     } 
private:   
     shared_ptr<IFactory> pFactory_; 
}; 

संपादित करें:

या अपने संदर्भ के आधार पर।

template<typename Factory> 
class Node 
{ 
public: 
     virtual ~Node(){} 

     Node() : pFactory_(new Factory()) 
     {   
     } 

     const shared_ptr<IFactory>& GetFactory() 
     { 
      return pFactory_; 
     } 
private:   
     shared_ptr<IFactory> pFactory_; 
}; 

class AreaNode : public Node<AreaNodeFactory> 
{ 
    // Implementation 
}; 

// OR 

typedef Node<AreaNodeFactory> AreaNode; 
+0

अच्छा विचार - हालांकि आप कारखानों के बारे में जानने के बारे में नोड्स के पूरे विचार के बारे में क्या सोचते हैं? उपरोक्त कर्ट सोचता है कि यह एक बुरा विचार है, हालांकि मैं आगंतुक पैटर्न के बिना कम से कम * कुछ * जानने के नोड्स के आस-पास एक साफ तरीके से नहीं सोच सकता। – Mark

+0

उन उदाहरणों में से कोई भी वास्तव में काम नहीं करता है। पहले मामले में आप प्रत्येक फैक्ट्री के लिए एक अलग एरिया नोड प्रकार के साथ समाप्त होते हैं - फैक्टरी प्रकार आंतरिक होना चाहिए और कक्षा के प्रकार से अवगत होने की आवश्यकता नहीं है। दूसरे मामले में नोड इंस्टेंटेशन में से कोई भी एक सामान्य बेस क्लास साझा नहीं करता है। –

+0

पहला उदाहरण केवल कन्स्ट्रक्टर को टेम्पलेट करके ही सुधार किया जा सकता है - यह उस वर्ग का एकमात्र हिस्सा है जिसे कारखाने के प्रकार को जानने की आवश्यकता है। –

1

"नोड" के प्रयोजन पर निर्भर करता है वस्तुओं

एक कारखाने एक नोड में इंजेक्शन और ठोस नोड के लिए नहीं है होना चाहिए, तो कारखाने के ठोस प्रकार के साथ कुछ भी करें तो सभी फैक्ट्री से संबंधित कोड को बेस नोड क्लास में सब कुछ सरल बनाने के लिए स्थानांतरित किया जा सकता है।

class INode //well, it's not "interface" in clear sense 
{ 
public: 
    void setFactory(Factory* f) { this->f = f; } 
    Factory* getFactory() const { return f; } 
private: 
    Factory* f; 
}; 

अब, ठोस नोड्स और ठोस कारखानों की कार्यक्षमता एक दूसरे के लिए ओर्थोगोनल किया जाता है और स्वतंत्र रूप से किसी भी तरह से जोड़ा जा सकता है।

यदि ठोस प्रकार का नोड फैक्ट्री के ठोस प्रकार से बंधे हैं, तो हो सकता है कि आपको कारखानों से बचें और सीधे नोड :: createView विधि के साथ विचार बनाएं। इस बात पर निर्भर करता है कि कारखानों का उपयोग किसी अन्य संदर्भ में किया जाता है या नहीं।

इसके अलावा इस (बहुत नहीं OOP-ish रास्ता) पर विचार करें:

typedef boost::function0<Factory*> Node; 
std::map<UIItem*,Node> nodes; 
nodes[area_item1] = &getAreaFactory; 
nodes[area_item2] = &getAreaFactory; 
nodes[region_item1] = &getRegionFactory; 
... 
void OnSelect(UIItem* i) 
{ 
    ... 
    View* v = nodes[i]()->createView(); 
    ... 
} 

शायद, यह सूट अपने सभी जरूरतों को)

संबंधित मुद्दे