2010-08-02 12 views
6

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

(कृपया ध्यान दें इस अर्द्ध छद्म कोड है)

उपयोगकर्ता क्लिक करता है नोड और नोड बाद में उपयोग के लिए भंडारित किया जाता है:

void onAddClicked() 
{ 
    IFactory *factory = selectedNode->getFactory(); 
    Dialog *dialog = factory->createAddDialog(parentWidget); 
    dialog->show(); 
} 

सब ठीक लग रहा है कौन सा:

void onTreeNodeSelected(INode *node) 
{ 
    selectedNode = node; 
} 

उपयोगकर्ता यूजर इंटरफेस पर "जोड़ें" क्लिक करता है। समस्या तब आती है जब मैं चयनित नोड को संपादित करना चाहता हूं:

void onEditClicked() 
{ 
    IFactory *factory = selectedNode->getFactory(); 
    Dialog *dialog = factory->createEditDialog(selectedNode, parentWidget); 
    dialog->show(); 
} 

ओह प्रिय .. मैं एक इनोड ऑब्जेक्ट में जा रहा हूं। किसी बिंदु पर मुझे सही नोड प्रकार के लिए डाउनकास्ट करना होगा ताकि संवाद ठीक से इसका उपयोग कर सके।

मैंने "PostgreSQL व्यवस्थापक 3" स्रोत कोड का अध्ययन किया है, और वे इसके समान कुछ करते हैं। वे ऐसा कुछ करने से गोल करते हैं:

FooObjectFactoryClass::createDialog(IObject *object) 
{ 
    FooObjectDialog *dialog = new FooObjectDialog((FooObject*)object); 
} 

येक .. कास्ट!

FooNode : INode 
{ 
    FooNodeFactory* FooNode::getFactory() 
    { 
     fooNodeFactory->setFooNode(this); 
     return fooNodeFactory; 
    } 
} 

तो फिर मेरे संपादन घटना यह कर सकते हैं:

एक ही रास्ता मैं इसे चारों ओर सोच सकते हैं और अभी भी अपने कारखानों उपयोग करने में सक्षम होने से पहले ही दिया जाता है कारखाने में नोड खुद इंजेक्षन करने के लिए है

void onEditClicked() 
{ 
    IFactory *factory = selectedNode->getFactory(); 
    Dialog *dialog = factory->createEditDialog(parentWidget); 
    dialog->show(); 
} 

और यह संदर्भ के लिए इंजेक्शन नोड का उपयोग करेगा।

मुझे लगता है कि कोई इंजेक्शन कोड नहीं है, तो createEditDialog झूठी या कुछ कह सकता है।

कोई विचार?

धन्यवाद!

उत्तर

3

एक आम समाधान "डबल-डिस्पैच" है, जहां आप एक ऑब्जेक्ट पर वर्चुअल फ़ंक्शन कहते हैं, जो बदले में वर्चुअल फ़ंक्शन को दूसरे पर कॉल करता है, this पास करता है, जिसमें अब सही स्थिर प्रकार है।

class IFactory 
{ 
public: 
    .... 
    virtual Dialog* createEditDialog(ThisNode*, IWidget*); 
    virtual Dialog* createEditDialog(ThatNode*, IWidget*); 
    virtual Dialog* createEditDialog(TheOtherNode*, IWidget*); 
    .... 
}; 

तो नोड के प्रत्येक प्रकार के एक आभासी createEditDialog कि सही कारखाने कार्य करने के लिए डिस्पैच है:

class INode 
{ 
public: 
    .... 
    virtual Dialog* createEditDialog(IWidget* parent) = 0; 
    .... 
}; 

class ThisNode : public INode 
{ 
public: 
    .... 
    virtual Dialog* ThisNode::createEditDialog(IWidget* parent) 
    { 
     return getFactory()->createEditDialog(this, parent); 
    } 
    .... 
}; 
तो, आपके मामले में, कारखाने संवादों के विभिन्न प्रकार के लिए काम करता है "बनाने के" शामिल कर सकते हैं

तो फिर तुम के रूप में

void onEditClicked() 
{ 
    Dialog *dialog = selectedNode->createEditDialog(parentWidget); 
    dialog->show(); 
} 
1

मेरी राय में, सी-शैली का उपयोग करते हुए (हालांकि सी ++ शैली को प्राथमिकता दी जाएगी) पूरी तरह स्वीकार्य है जब तक आपका कोड ठीक से टिप्पणी नहीं करता है।

मैं डीआई (dependency injection) का बड़ा प्रशंसक नहीं हूं क्योंकि यह कुछ कोडों का पालन करने में कठोर बनाता है और, आपके मामले में, मैं dynamic_cast<>() या एकाधिक स्रोत फ़ाइलों पर इंजेक्शन कोड का पालन करने की कोशिश करने के बजाय कुछ देखता हूं।

0

मैं दो चीजों का सामना करूंगा।

पहला: कास्टिंग के साथ कुछ भी गलत नहीं है। अगर आप सुरक्षित रहना चाहते हैं, तो आप आरटीटीआई (टाइप_आईडी सामान) या इनोड क्लास में कुछ आभासी कार्यों का उपयोग कर सकते हैं जो कुछ जानकारी वापस कर सकते हैं जो आपको बताएंगे कि यह सुरक्षित है या नहीं।

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

आम तौर पर, मुझे आपके द्वारा वर्णित समस्या के साथ वास्तव में कुछ भी गलत नहीं लगता है, और पूरे कोड को देखे बिना अधिक सुझाव देना मुश्किल है, जो मुझे लगता है कि यह असुरक्षित है।

0

सही संवाद बना सकते हैं कारखाने में नोड इंजेक्शन लगाने के अपने दृष्टिकोण आम तौर पर एक पैटर्न जो मुझे उपयोगी है, लेकिन अक्सर कई बार जब आप लक्ष्य वस्तु का संदर्भ नहीं लेते हैं तो आप यहां फैक्ट्री बना रहे हैं जैसे आप यहां करते हैं। तो यह इस मामले में आपके लिए ठीक काम कर सकता है और सामान्य मामले में इस तरह की समस्या को संभालने से आसान है।

अधिकतर सामान्य मामले के लिए, आप इंटरफेस की धारणा के साथ काम करते हैं और एक व्यवस्था है जिसके द्वारा अपने INode वस्तु प्रकाशित कर सकते हैं जो इंटरफेस का समर्थन करता है स्थापित करने और ग्राहकों के लिए उन इंटरफेस के लिए पहुँच प्रदान करने की जरूरत है। यह पूरी तरह से गतिशील रूप से ऐसा करने के लिए एक COM-like दृष्टिकोण की ओर जाता है जिसके लिए गतिशील पंजीकरण और कास्टिंग की आवश्यकता होती है। लेकिन यदि आप एक नया घटक इंटरफ़ेस जोड़ने की आवश्यकता है तो आप INode इंटरफ़ेस को संपादित करने के लिए इंटरफ़ेस का अपेक्षाकृत स्थिर सेट सेट कर सकते हैं और आप इसे स्थिर रूप से टाइप किए गए तरीके से भी कर सकते हैं।

तो यह कैसे सरल स्थिर टाइप किया दृष्टिकोण करने के लिए का एक उदाहरण होगा:

struct INode 
{ 
    virtual INodeSize* getNodeSizeInterface() = 0; 

    virtual INodeProperties* getNodePropertiesInterface() = 0; 

    virtual INodeColor* getNodeColorInterface() = 0; 

    ... // etc 
} 

अब प्रत्येक INode कार्यान्वयन इनमें से कुछ या घटक इंटरफेस के सभी लौट सकते हैं (यह सिर्फ वापसी होगी शून्य अगर यह नहीं था ' टी उन्हें लागू करता है)। फिर आपके संवाद घटक इंटरफेस पर काम करते हैं ताकि यह पता लगाने की कोशिश की जा सके कि INode का वास्तविक कार्यान्वयन किस प्रकार किया गया था। यह संवाद और नोड कार्यान्वयन के बीच अधिक लचीली मैपिंग के लिए तैयार होगा। एक संवाद जल्दी से निर्धारित कर सकता है कि क्या यह "संगत" INode ऑब्जेक्ट है, यह सत्यापित करके कि यह प्रत्येक इंटरफ़ेस के लिए एक वैध ऑब्जेक्ट देता है जिसमें संवाद रुचि है।

0

मुझे लगता है कि createEditDialog के अंदर एक कास्ट इस मामले में एक बुरी बात नहीं है , भले ही आप संकलन समय जांच छोड़ दें। यदि रनटाइम पर नोड का प्रकार नहीं बदलता है, तो आप एक सार INode -class के बजाय टेम्पलेट का उपयोग कर सकते हैं।

अन्यथा, आपका प्रस्तावित समाधान वह है जिसे मैं भी सोचूंगा। हालांकि, मैं "getSelectedNodeDialogFactory" (मुझे पता है, लंबा नाम) जैसे कुछ तरीके का नाम बदलना होगा ताकि यह स्पष्ट हो कि कारखाना लौटाया गया नोड उस विशिष्ट के लिए विशिष्ट है। क्या ऐसे अन्य संवाद हैं जिन्हें INode ऑब्जेक्ट के ठोस प्रकार को जानने की आवश्यकता है? क्या createAddDialog को माता-पिता या पूर्ववर्ती नोड की आवश्यकता है, शायद? वे सभी कारखाने के साथ-चयनित-नोड कक्षा में जा सकते हैं।

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