2009-07-03 10 views
6

लाइब्रेरी/उपयोगिता को कॉन्फ़िगर करने के लिए सी एपीआई डिज़ाइन करते समय, मेरे पास एक सहकर्मी होता है जो सभी कॉन्फ़िगरेशन पैरामीटर को 1 फ़ंक्शन कॉल में लंप करना पसंद करता है। उदाहरण के लिए:सी कॉन्फ़िगरेशन API

int set_diagnostic_email_config(char *to_address, 
           bool include_timestamp, 
           bool send_for_crashes, 
           bool send_daily_status, 
           bool send_on_event1, 
           bool send_on_event2) 

ऐसा ही एक "मिल" समारोह कई मापदंडों के साथ मौजूद है .. इस विधि का मुख्य लाभ यह है कि अगर किसी को एक नया विकल्प, कहते हैं जैसे, "bool send_on_event3", तो क्योंकि प्रोटोटाइप आप बदल है इस फंक्शन कॉल का उपयोग हर जगह अपडेट करने के लिए मजबूर किया जाता है (माना जाता है कि वहां कई जगहें हैं जहां लोग इसे कॉल करते हैं)। आवश्यकतानुसार

int get_diagnostic_email_config(struct email_config *p_config); 
int set_diagnostic_email_config(struct email_config *p_config); 

जहां सिर्फ संरचना तत्वों को परिवर्तित:

मैं की तर्ज पर कुछ पसंद करते हैं। लेकिन ... अगर कोई ईमेल_कॉन्फिग "संरचना को अपडेट करता है तो यह लोगों को उन सभी स्थानों को अपडेट करने के लिए मजबूर नहीं करता है जहां यह उपयोग किया जाता है (भले ही हम अक्सर .. ..) इसके अलावा मेरे सहकर्मी शिकायत करते हैं कि अगर कोई प्रारंभ करने की कोशिश करता है हाथ से "email_config", फिर यदि चीजें बाद में जुड़ जाती हैं तो उन नए फ़ील्ड को कोई चेतावनी के साथ अनियंत्रित किया जाएगा।

क्या कोई मजबूत सहमति है कि किस विधि को प्राथमिकता दी जाती है? या शायद एक और विकल्प है जो मुझे याद आ रहा है?

उत्तर

11

एक संरचना लंबी सूची से बेहतर है। लंबी सूची को बनाए रखना मुश्किल है, क्योंकि कोई भी सही क्रम को याद नहीं करता है।

आप एक रचनाकार बना सकते हैं जो इस संरचना को सुरक्षित (डिफ़ॉल्ट और/या अमान्य) प्रविष्टियों से भरता है। हमेशा (संभवतः एक्सेसर फ़ंक्शन में) अमान्य मानों की जांच करने से प्रारंभिकरण में त्रुटियों को स्थानांतरित करना आसान हो जाएगा।

आप इस संरचना में एक जादू संख्या छुपा सकते हैं। पहला क्षेत्र CONFIG_MAGIC है जिसे परिभाषित स्थिरता के बराबर होना चाहिए। आप इस क्षेत्र को कन्स्ट्रक्टर में सेट करते हैं और हर समय सेट होने की उम्मीद करते हैं। यह आप किसी व्यक्ति से केवल malloc() संरचना से बचने और इसे हाथ से initalizing से बचें। इस तरह के प्रोग्रामर को इस CONFIG_MAGIC निरंतरता के बारे में जानने की आवश्यकता होगी और उचित कन्स्ट्रक्टर को खोजने और उपयोग करने की संभावना से अधिक है।

+0

+1। उत्कृष्ट सलाह। – DevSolar

+1

+1 मूल रूप से यह ओओपी है - परिवर्तनों को प्रबंधित करना आसान है, सफाई के प्रारंभ में प्रारंभ करने के लिए राज्य - कन्स्ट्रक्टर/विनाशक के साथ कार्यान्वयन रखें – stefanB

+0

धन्यवाद! मुझे विशेष रूप से CONFIG_MAGIC विचार पसंद है। – Will

0

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

0

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

3

मैं निम्नलिखित तरीके का उपयोग करूंगा जो आपके रास्ते का विस्तार है।

struct INFO 
{ 
    char *to_address; 
    bool include_timestamp; 
    bool send_for_crashes; 
    bool send_daily_status; 
    bool send_on_event1; 
    bool send_on_event2; 
}; 

struct INFO *createINFO() 
{ 
    // initialize to defaults. 

    // return a pointer to the new created struct. 
} 

void include_timestamp(struct INFO *info, bool vInclude_timestamp) 
{ 
    // set the field. 
} 

// add the required setters... 

void destroyINFO(struct INFO *info) 
{ 
    // destroy the struct. 
} 

इस तरह, आप, मांग पर 'setters' जोड़ने जब कभी आप एक नए क्षेत्र में जोड़ सकते हैं। उपयोगकर्ता को संरचना के साथ गड़बड़ करने की अनुमति के बिना।

+0

मैं इन स्मृति प्रबंधन कार्यों को नहीं करना चाहूंगा। –

+0

अच्छी तरह से, आप सही हैं :) – AraK

0

मैं

int set_diagnostic_email_config(char *to_address, 
           bool include_timestamp, 
           int event_type) { 
    switch (event_type) { 
     case 1: 
     ... 
    } 
} 

या

int set_diagnostic_email_config(char *to_address, 
           bool include_timestamp, 
           int event_type, void *details) 

का उपयोग करने के बाद एक event_type रूप में एक पूर्णांक आप हस्ताक्षर को बदले बिना नई घटना में जोड़ सकते हैं इसका मतलब होगा। एक अतिरिक्त void* प्रत्येक ईवेंट प्रकार के लिए वैकल्पिक संरचना प्रदान करता है।

यदि आप struct का उपयोग करते हैं, तो इसमें परिवर्तन हमेशा बाइनरी संगत नहीं हो सकते हैं।

3

लंबी पैरामीटर सूचियां पठनीय नहीं हैं, विशेष रूप से यदि यह बूल की एक सूची है। हर बार एक समारोह कॉल है कि इस तरह दिखता है के लिए आते हैं:


    set_diagnostic_email_config("[email protected]", 0, 1, 0, 1, 0, 1, 0, 0, 0); 

आप प्रलेखन की जांच के लिए देखने के लिए क्या इस अंकों पैटर्न के लिए अच्छा है। और यदि आप फ़ंक्शन का उपयोग कर रहे हैं, तो आप कुछ मामलों में कुछ सैने डिफ़ॉल्ट, यानी उपयोग करना चाहते हैं। आप इस लाइन को कहीं और से कॉपी करने में समाप्त होते हैं।

यदि आपके पास केवल बुलियन मूल्य हैं, तो मैं झंडे का उपयोग करता हूं, जिसे आप ऑरिंग के साथ जोड़ सकते हैं। यहाँ एक संभव उदाहरण है:,

 
    set_diagnostic_email_config("[email protected]", FLAG_SEND_DAILY_STATUS | FLAG_SEND_ON_EVENT1); 

इस कोड को पढ़ने के लिए आसान है, आप इसे समझने के लिए हर विकल्प पता करने की जरूरत नहीं है:


    typedef enum { 
     FLAG_DEFAULT = 0, 
     FLAG_INCLUDE_TIMESTAMP = 0x1, 
     FLAG_SEND_FOR_CRASHES = 0x2, 
     FLAG_SEND_DAILY_STATUS = 0x4, 
     FLAG_SEND_ON_EVENT1 = 0x8 
    } Email_Flags; 

    int set_diagnostic_email_config(const char *address, unsigned int flags); 

अब आप इस तरह समारोह कॉल कर सकते हैं। और यह कोड लिखना आसान है, क्योंकि "पैरामीटर" (वास्तव में झंडे का क्रम) का क्रम महत्वपूर्ण नहीं है। और यह फ़ंक्शन विस्तार करना आसान है, आप बस अधिक झंडे जोड़ सकते हैं, मान लें कि FLAG_SEND_ON_EVENT2 और जब तक आप अपना व्यवहार बदलना चाहते हैं, तब तक आपको कोई फ़ंक्शन कॉल बदलने की आवश्यकता नहीं है।

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