2012-09-04 12 views
6

के लिए बहुत सारे कन्स्ट्रक्टर Args तो मैंने निर्भरता इंजेक्शन के साथ फैक्टरी डिजाइन पैटर्न का उपयोग करने का निर्णय लिया।निर्भरता इंजेक्शन/विरासत डिजाइन पैटर्न

class ClassA 
{   
    Object *a, *b, *c; 
    public: 
    ClassA(Object *a, Object *b, Object *c) : 
    a(a), b(b), c(c) {} 
}; 

class ClassB : public ClassA 
{   
    Object *d, *e, *f; 
    public: 
    ClassB(Object *a, Object *b, Object *c, Object *d, Object *e, Object *f) : 
    ClassA(a, b, c), d(d), e(e), f(f) {} 
}; 

अब, समस्या यह है कि classB निर्माता के लिए भी कई तर्क है। यह एक एकल विरासत-परत उदाहरण है, लेकिन जब विरासत परतें गहरी हो रही हैं, और जब प्रत्येक लेयर-क्लास को और अधिक वस्तुओं की आवश्यकता होती है, तो शीर्ष परत में निर्माता को बनाने के लिए बहुत से तर्कों की आवश्यकता होती है!

मुझे पता है कि मैं निर्माता के बजाए सेटर्स का उपयोग कर सकता हूं, लेकिन क्या कोई और तरीका है?

+12

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

+2

माइक सेमुर सही है। एक रिश्ते (विरासत) को अधिक कसकर युग्मित करने के लिए एक रिश्ता (रचना) पसंद करते हैं। शायद अगर आप समझाते हैं कि आप क्या करना चाहते हैं, तो हम आपको बता सकते हैं कि इसे पूरा करने के लिए कितना बेहतर है? – metal

+2

मुझे विरासत के साथ कोई बड़ी समस्या नहीं दिख रही है। इसे हर जगह इस्तेमाल किया जाना चाहिए जहां इसकी आवश्यकता है। यह सब कुछ के रूप में दुरुपयोग नहीं किया जाना चाहिए। –

उत्तर

1

यह सी ++ समस्याओं में से एक है (यदि इसे कोई समस्या कहा जा सकता है)। इसमें सीटीओ न्यूनतम के पैरामीटर की संख्या रखने की कोशिश करने के अलावा समाधान नहीं है।

दृष्टिकोण से एक रंगमंच की सामग्री का उपयोग कर रहा तरह struct:

struct PropsA 
{ 
    Object *a, *b, *c; 
}; 

class ClassA 
{ 
    ClassA(PropsA &props, ... other params); 
}; 

यह स्पष्ट लगता है, लेकिन मैं इस के लिए कई बार इस्तेमाल किया था। कई मामलों में यह पता चला है कि पैराम के कुछ समूह संबंधित हैं। इस मामले में उनके लिए एक संरचना को परिभाषित करना समझ में आता है।

इस प्रकार का मेरा सबसे बुरा दुःस्वप्न पतली रैपर कक्षाओं के साथ था। आधार के तरीकों और डेटा फ़ील्ड को सीधे एक्सेस किया जा सकता है जबकि सभी सीटीआर को डुप्लिकेट किया जाना चाहिए। जब 10+ सीटीआर होते हैं, तो एक रैपर बनाने में समस्या होती है।

+0

ज्यादातर मामलों में, इसमें 'प्रॉप्सए' को एक पूर्ण श्रेणी में संबंधित तरीकों को दबाकर भी समझदारी होगी। अन्यथा आप केवल एक डेटा संरचना के साथ समाप्त हो जाते हैं जो बहुत ऑब्जेक्ट उन्मुख नहीं है। – casablanca

+1

मैंने ऐप की आवश्यकताओं, ऑब्जेक्ट ओरिएंटेड "होने की फैंसी चीजों से पहले एफएआर एफएआर कोड की विकास और स्पष्टता की गति डाली। –

+1

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

6

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

ClassBBuilder { 
    public: 
    ClassBBuilder& setPhoneNumber(const string&); 
    ClassBBuilder& setName(consg string&); 
    ClassBBuilder& setSurname(const string&); 
    ClassB* build(); 
} 

की तरह किसी भी तरह देख सकते हैं और अगर आप बिल्डर को यह पसंद का उपयोग करें:

ClassB* b = ClassBBuilder().setName('alice').setSurname('Smith').build(); 

निर्माण() विधि जांच करता है कि सभी आवश्यक पैरामीटर स्थापित किए गए थे और यह या तो रिटर्न ठीक से वस्तु का निर्माण या शून्य। आंशिक रूप से निर्मित वस्तु बनाना असंभव है। आपके पास अभी भी कई तर्कों के साथ एक कन्स्ट्रक्टर है, लेकिन यह निजी है और केवल एक ही स्थान पर बुलाया जाता है। ग्राहक इसे नहीं देख पाएंगे। बिल्डर विधियां भी अच्छी तरह से दस्तावेज करती हैं कि प्रत्येक पैरामीटर का अर्थ क्या है (जब आप कक्षाबी ('foo', 'bar') देखते हैं तो आपको यह पता लगाने के लिए कि कौन सा पैरामीटर नाम है और कौन सा उपनाम है) को कन्स्ट्रक्टर की जांच करने की आवश्यकता है। -

+0

यह सेटर्स की तुलना में थोड़ा अच्छा हो सकता है, लेकिन आप प्रभावी रूप से देरी कर रहे हैं रनटाइम पर ऑब्जेक्ट बनाने के लिए पर्याप्त जानकारी के लिए जांच मौजूद है। मुझे नहीं लगता कि एक सादे कन्स्ट्रक्टर पर कुछ तर्क लेने में सुधार। –

+0

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

+1

मुझे यह दृष्टिकोण पसंद है। ऑब्जेक्ट का निर्माण करने वाले क्लाइंट के लिए कोड बहुत साफ है। हालांकि यह सच है कि आप संकलन समय की जांच खो देते हैं, बिल्ड() फ़ंक्शन अभी भी आपके कोड में सत्यापन जांच के लिए अनुमति देता है। –

1

मुझे लगता है कि क्या आप का वर्णन कर रहे हैं C++ एक समस्या नहीं है, वास्तव में, सी ++ निर्भरता काफी अच्छी तरह से अपने डिजाइन द्वारा व्यक्त दर्शाता है:

  1. प्रकार ClassA की एक वस्तु का निर्माण करने के लिए आप की आवश्यकता है तीन Object उदाहरण (a, b और c)।
  2. ClassB प्रकार का ऑब्जेक्ट बनाने के लिए, आपको तीन Object उदाहरण (d, e और f) की आवश्यकता होगी।
  3. ClassB के प्रत्येक ऑब्जेक्ट को ClassA के प्रकार की तरह माना जा सकता है।

इसका मतलब है कि प्रकार का ऑब्जेक्ट के निर्माण के लिए ClassB आप तीन Object वस्तुओं जो ClassA इंटरफ़ेस के कार्यान्वयन के लिए आवश्यक हैं, और उसके बाद ClassB इंटरफ़ेस के कार्यान्वयन के लिए एक और तीन प्रदान करने के लिए की जरूरत है।

मुझे विश्वास है कि वास्तविक समस्या यहां आपका डिज़ाइन है। आप इस को हल करने विभिन्न दृष्टिकोणों पर विचार कर सकते:

  1. मत ClassB इनहेरिट ClassA। हो सकता है कि आप किसी भी प्रकार की ऑब्जेक्ट्स के समरूप पहुंच की आवश्यकता के आधार पर एक विकल्प हो या नहीं हो सकते (कहें, क्योंकि आपके पास ClassA* का संग्रह है और इस संग्रह में ClassB पर पॉइंटर्स भी शामिल हो सकते हैं)।
  2. वस्तुओं की तलाश करें जो हमेशा एक साथ दिखाई देते हैं। पसंद है - हो सकता है कि पहले दो ऑब्जेक्ट्स या तो कन्स्ट्रक्टर (a और b या d और e) को पारित किया गया हो, तो कुछ प्रकार की जोड़ी का प्रतिनिधित्व करें। शायद एक वस्तु पहचानकर्ता या पसंद है? इस मामले में, इसके लिए एक समर्पित सार (पढ़ना: प्रकार) पेश करना फायदेमंद हो सकता है।
संबंधित मुद्दे