2012-06-17 11 views
11

परमाणुता के लिए इंटेलिजेंस और एटमिनर के लिए माइक्रोसॉफ्ट का धन्यवाद ... इन सभी पैरामीटर आवश्यक और अपरिवर्तनीय हैं।एक 13-पैरामीटर कन्स्ट्रक्टर

क्या ऐसा करने का कोई बेहतर तरीका है?

/************************************************************************************************** 
* <summary>Initializes a new instance of the ADTBattleCharacter class.</summary> 
* <param name="name">   The name of the character.</param> 
* <param name="max_HP">  The maximum hit points.</param> 
* <param name="max_MP">  The maximum magic power.</param> 
* <param name="strength">  The strength.</param> 
* <param name="agility">  The agility.</param> 
* <param name="attack_power"> The attack power.</param> 
* <param name="defense_power">The defense power.</param> 
* <param name="gold">   The gold carried by the character.</param> 
* <param name="experience"> The experience the character is worth.</param> 
* <param name="stop_resist"> The character's resistance to stopspell.</param> 
* <param name="sleep_resist"> The character's resistance to sleep.</param> 
* <param name="hurt_resist"> The character's resistance to hurt/hurtmore.</param> 
* <param name="spell_list"> Available spells.</param> 
**************************************************************************************************/ 
ADTBattleCharacter(std::string name, unsigned char max_HP, unsigned char max_MP, 
        unsigned char strength, unsigned char agility, 
        unsigned char attack_power, unsigned char defense_power, 
        unsigned short gold, unsigned short experience, 
        double stop_resist, double sleep_resist, double hurt_resist, 
        std::bitset<SPELL_MAX> spell_list); 
+2

आप उन्हें सभी कंटेनर ऑब्जेक्ट में पैक नहीं कर सकते हैं और इसके बजाय पास कर सकते हैं? –

+1

एक स्ट्रक्चर में एम रखें, डिफॉल्ट वैल्यू दें या दूसरों के कुछ बंद करें, अपनी जरूरतों को बदलें, और स्ट्रक्चर को पास करें? – chris

+0

@ क्रिस, जो सिर्फ संरचना के निर्माता को समस्या को पेंट करता है। वास्तव में कुछ भी नहीं बदलता है। –

उत्तर

33

अपने विशिष्ट मामले को देखते हुए, ऐसा लगता है कि आपने चीजों को बहुत अच्छी तरह से तोड़ा नहीं है।

वैचारिक रूप से, अपने सिस्टम में एक चरित्र है:

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

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

उदाहरण के लिए, आप एक चरित्र का स्टेट ब्लॉक प्रदर्शित करना चाह सकते हैं। क्या यह कार्य वास्तव में वर्ण की आवश्यकता है? नहीं; यह सिर्फ स्टेट ब्लॉक की जरूरत है। तो इसे एक स्टेट ब्लॉक ऑब्जेक्ट लेना चाहिए।

बस चरित्र के निर्माता की तरह ही।

+4

+1 जैसा कि एलन जे पर्लिस ने कहा: "यदि आपके पास दस पैरामीटर के साथ एक प्रक्रिया है, तो शायद आप कुछ चूक गए।" –

+0

मैं आपका बिंदु देखता हूं, लेकिन "ऑब्जेक्ट के साथ पैरामीटर को प्रतिस्थापित करें" रिफैक्टर समस्या को कम नहीं करता है, बस इसे दूसरे स्थान पर ले जाता है। यह केवल इस कन्स्ट्रक्टर में 4 हो सकता है, लेकिन जब उन 4 वर्गों के मानकों को ध्यान में रखा जाता है, तो यह अभी भी 13. – Casey

+2

@Casey: तो? 4 वर्गों में फैले 13 पैरामीटर प्रति कन्स्ट्रक्टर के 3.25 पैरामीटर का औसत है। क्या निर्माता के लिए 4 पैरामीटर रखने में कोई समस्या है? क्या आप 8 पैरामीटर लेने के लिए 4 डी वेक्टर डॉट-उत्पाद फ़ंक्शन पर विचार करते हैं? नहीं; इसमें 2 लगते हैं, जो कि प्रत्येक में 4 मान होते हैं। फिर, यह सिर्फ * इस * समारोह के बारे में नहीं है; यह डेटा के उचित संगठन के बारे में है। एक 4 डी वेक्टर * एक ऑब्जेक्ट * है, इससे कोई फर्क नहीं पड़ता कि इसके रचनाकार कितने पैरामीटर लेते हैं। जैसे एक स्टेट ब्लॉक एक ही वस्तु है, इससे कोई फर्क नहीं पड़ता कि इसमें कितने आंकड़े हैं। –

0

यदि लक्ष्य केवल कन्स्ट्रक्टर को दिए गए तर्कों की संख्या को कम करने के लिए है, तो इसे प्राप्त करने के कई तरीके हैं। वास्तविक सवाल यह है कि, जैसा कि मैं टिप्पणियों से अपनी पहली पोस्ट में समझता हूं, यह है कि पैरामीटर को प्रबंधित करने का एक आसान तरीका है।

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

enum AttrTag { AT_Name, AT_Max_HP, AT_Max_MP, //... 
       AT_Spells }; 

struct Attributes { 
    typedef std::unique_ptr<AttrBase> AttrPtr; 
    typedef std::map<AttrTag, AttrPtr> AttrMap; 
    AttrMap attributes; 

    template <AttrTag TAG> 
    typename Attr<TAG>::value_type get_attr() const { 
     AttrMap::const_iterator i = attributes.find(TAG); 
     if (i != attributes.end()) return i->second->attr_cast<TAG>()->value; 
     return Attr<TAG>::default_value; 
    } 

    template <AttrTag TAG> 
    void set_attr (typename Attr<TAG>::value_type value) { 
     attributes[TAG] = AttrPtr(new Attr<TAG>(value)); 
    } 

    bool has_attr (AttrTag t) const { 
     return attributes.find(t) != attributes.end(); 
    } 

}; 

और यह इस तरह इस्तेमाल किया जाएगा:

Attributes attrs; 
attrs->set_attr<AT_Gold>(100); 
//... 
ADTBattleCharacter(attrs); 
//... 
unsigned short g = attrs->get_attr<AT_Gold>(); 

विशेषताओं AttrBase वर्ग कि पता होगा वास्तविक विशेषता को सौंपने के लिए कैसे बाहर आ जाएगा।

template <AttrTag> struct Attr; 

struct AttrBase { 
    virtual ~AttrBase() {} 
    template <AttrTag TAG> Attr<TAG> * attr_cast() { 
     return dynamic_cast<Attr<TAG> *>(this); 
    } 
}; 

और विशेषताओं को AttrBase से विरासत एक Attr टेम्पलेट विशेषज्ञता से बनाया जा जाएगा।

template <AttrTag TAG> 
struct Attr : public AttrBase { 
    typedef unsigned char value_type; 
    enum { default_value = 0 }; 
    value_type value; 
    Attr (value_type v) : value(v) {} 
}; 

template <> 
struct Attr<AT_Name> : public AttrBase { 
    typedef std::string value_type; 
    static std::string default_value; 
    value_type value; 
    Attr (value_type v) : value(v) {} 
}; 

template <> 
struct Attr<AT_Gold> : public AttrBase { 
    typedef unsigned short value_type; 
    enum { default_value = 1 }; 
    value_type value; 
    Attr (value_type v) : value(v) {} 
}; 

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

+0

कृपया नीचे दिए गए वोट पर टिप्पणी करें, इसलिए, मुझे पता है कि क्या ठीक करना है। धन्यवाद! – jxh

+2

-1: यह * बहुत खराब * है। कम से कम कई पैरामीटर के साथ कन्स्ट्रक्टर के साथ, पैरामीटर के उचित नाम हैं। उनके सी ++ मूल प्रकार द्वारा ग्रुपिंग विशेषताएं कार्यात्मक रूप से * अर्थहीन * है। यदि आप उन्हें समूहित करने जा रहे हैं, तो ऐसा कुछ करें जो वास्तव में कुछ है। –

+2

यह जटिलता को कम करने के लिए कुछ भी नहीं करता है और इसे अधिक अस्पष्ट बनाता है। 'कॉन्फ़िगरेशन' ऑब्जेक्ट या कुछ ऐसा जो कि तर्कों को समाहित करता है, को पार करना बेहतर होता है। – seand

1

बेहतर तरीका Builder design pattern का उपयोग करना है। या, अधिक सरलता से, आप उस वर्ग को घोषित कर सकते हैं जिसमें आपके वर्तमान कन्स्ट्रक्टर के सभी पैरामीटर के लिए फ़ील्ड शामिल हैं। पैरामीटर क्लास में स्वयं एक कन्स्ट्रक्टर (या कन्स्ट्रक्टर) हो सकता है जो फ़ील्ड को उचित डिफ़ॉल्ट मानों में प्रारंभ करता है, और आप फ़ील्ड्स को सीधे एक्सेस करके मान बदलते हैं। फिर या तो अपनी ऑब्जेक्ट बनाने के लिए पैरामीटर क्लास में फ़ंक्शन को कार्यान्वित करें, या ऑब्जेक्ट कन्स्ट्रक्टर को परिभाषित करें जो पैरामीटर क्लास का उदाहरण लेता है।

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