क्या ध्वज चर एक पूर्ण बुराई हैं? [बन्द है]


47

क्या ध्वज चर बुराई हैं? निम्न प्रकार के चर गहनता से अनैतिक हैं और क्या उनका उपयोग करना दुष्ट है?

"बूलियन या पूर्णांक चर जो आप कुछ स्थानों पर एक मान निर्दिष्ट करते हैं, फिर नीचे आप चेक करते हैं फिर कुछ करने या न करने के लिए कक्षा में, उदाहरण के लिए, newItem = trueफिर नीचे कुछ पंक्तियों का उपयोग करते हुए if (newItem ) then"


मुझे याद है कि मैं कुछ ऐसे प्रोजेक्ट्स कर रहा हूँ जहाँ मैंने झंडे के इस्तेमाल की पूरी तरह से उपेक्षा की और बेहतर आर्किटेक्चर / कोड के साथ समाप्त हुआ; हालाँकि, यह उन अन्य परियोजनाओं में एक आम बात है जिन पर मैं काम करता हूं, और जब कोड बढ़ता है और झंडे जुड़ जाते हैं, तो IMHO कोड-स्पेगेटी भी बढ़ता है।

क्या आप कहेंगे कि ऐसे कोई मामले हैं जहां झंडे का उपयोग करना एक अच्छा अभ्यास है या यहां तक ​​कि आवश्यक है ?, या क्या आप सहमत होंगे कि कोड में झंडे का उपयोग कर रहे हैं ... लाल झंडे और बचना चाहिए / refactored; मुझे, मैं केवल उन कार्यों / विधियों को करके प्राप्त करता हूं जो वास्तविक समय में राज्यों की जांच करते हैं।


9
ऐसा लगता है कि मेनमा और मेरे पास "ध्वज" की एक अलग परिभाषा है। मैं प्रीप्रोसेसर #ifdefs सोच रहा था। आप किसके बारे में पूछ रहे थे?
कार्ल बेज़ेलफेल्ट

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

बुलियन झंडे हैं। (तो पूर्णांक हैं, इसलिए ...)
थॉमस एडिंग

7
@KarlBielefeldt मेरा मानना ​​है कि ओपी बूलियन या पूर्णांक चर का उल्लेख कर रहा है, जिसे आप कुछ स्थानों पर मान देते हैं, फिर नीचे आप जाँच करते हैं कि कुछ करने के लिए newItem = trueif (newItem ) then
परिक्रमा

1
इस संदर्भ में परिवर्तनशील चर का वर्णन करने वाले परिचय पर भी विचार करें । जब तक विधि कम रहती है और इसके माध्यम से कम संख्या में रास्ते होते हैं, मैं इसे एक वैध उपयोग मानता हूं।
डैनियल बी

जवाबों:


41

झंडे का उपयोग करने वाले कोड को बनाए रखने पर मैंने जो मुद्दा देखा है, वह यह है कि राज्यों की संख्या जल्दी से बढ़ती है, और लगभग हमेशा अखंड राज्य होते हैं। अपने स्वयं के अनुभव से एक उदाहरण: मैं कुछ कोड पर काम कर रहा था जिसमें ये तीन झंडे थे

bool capturing, processing, sending;

इन तीनों ने आठ राज्य बनाए (वास्तव में, दो अन्य झंडे भी थे)। सभी संभावित मूल्य संयोजन कोड द्वारा कवर नहीं किए गए थे, और उपयोगकर्ता बग देख रहे थे:

if(capturing && sending){ // we must be processing as well
...
}

यह पता चला कि ऐसी परिस्थितियाँ थीं जहाँ ऊपर दिए गए कथन में धारणा गलत थी।

झंडे समय के साथ मिश्रित होते हैं, और वे एक वर्ग की वास्तविक स्थिति को छिपाते हैं। इसीलिए इनसे बचना चाहिए।


3
+1, "बचना चाहिए"। मैं 'लेकिन कुछ स्थितियों में झंडे आवश्यक हैं' के बारे में कुछ जोड़ूंगा (कुछ कह सकते हैं कि 'एक आवश्यक बुराई')
ट्रेवर बॉयड स्मिथ

2
@TrevorBoydSmith मेरे अनुभव में वे नहीं हैं, आपको बस औसत मस्तिष्क की शक्ति की तुलना में थोड़ी अधिक आवश्यकता है जो आप एक ध्वज के लिए उपयोग करेंगे
dukeofgaming

आपके एग्जाम में यह 3 बूलियनों का प्रतिनिधित्व करने वाला एक एनम होना चाहिए।
user949300

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

38

यहां एक उदाहरण है जब झंडे उपयोगी होते हैं।

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

झंडे के साथ, इस विधि को कॉल करना आसान है:

var password = this.PasswordGenerator.Generate(
    CharacterSet.Digits | CharacterSet.LowercaseLetters | CharacterSet.UppercaseLetters);

और इसे सरल भी किया जा सकता है:

var password = this.PasswordGenerator.Generate(CharacterSet.LettersAndDigits);

झंडे के बिना, विधि हस्ताक्षर क्या होगा?

public byte[] Generate(
    bool uppercaseLetters, bool lowercaseLetters, bool digits, bool basicSymbols,
    bool extendedSymbols, bool greekLetters, bool cyrillicLetters, bool unicode);

इस तरह कहा जाता है:

// Very readable, isn't it?
// Tell me just by looking at this code what symbols do I want to be included?
var password = this.PasswordGenerator.Generate(
    true, true, true, false, false, false, false, false);

जैसा कि टिप्पणियों में कहा गया है, एक संग्रह का उपयोग करने के लिए एक और दृष्टिकोण होगा:

var password = this.PasswordGenerator.Generate(
    new []
    {
        CharacterSet.Digits,
        CharacterSet.LowercaseLetters,
        CharacterSet.UppercaseLetters,
    });

यह और अधिक पठनीय है के सेट की तुलना में trueऔर false, लेकिन अभी भी दो कमियां भी हैं:

मुख्य दोष यह है कि संयुक्त मूल्यों को अनुमति देने के लिए, जैसे CharacterSet.LettersAndDigitsआप Generate()विधि में ऐसा कुछ लिख रहे होंगे :

if (set.Contains(CharacterSet.LowercaseLetters) ||
    set.Contains(CharacterSet.Letters) ||
    set.Contains(CharacterSet.LettersAndDigits) ||
    set.Contains(CharacterSet.Default) ||
    set.Contains(CharacterSet.All))
{
    // The password should contain lowercase letters.
}

संभवतः इस तरह से फिर से लिखा गया है:

var lowercaseGroups = new []
{
    CharacterSet.LowercaseLetters,
    CharacterSet.Letters,
    CharacterSet.LettersAndDigits,
    CharacterSet.Default,
    CharacterSet.All,
};

if (lowercaseGroups.Any(s => set.Contains(s)))
{
    // The password should contain lowercase letters.
}

झंडे का उपयोग करके आपके पास इसकी तुलना करें:

if (set & CharacterSet.LowercaseLetters == CharacterSet.LowercaseLetters)
{
    // The password should contain lowercase letters.
}

दूसरा, बहुत मामूली दोष यह है कि यह स्पष्ट नहीं है कि अगर इस तरह कहा जाता है तो विधि कैसे व्यवहार करेगी:

var password = this.PasswordGenerator.Generate(
    new []
    {
        CharacterSet.Digits,
        CharacterSet.LettersAndDigits, // So digits are requested two times.
    });

10
मेरा मानना ​​है कि ओपी बूलियन या पूर्णांक चर को संदर्भित कर रहा है, जिसे आप कुछ स्थानों पर मान देते हैं, फिर नीचे आप चेक करते हैं, फिर कुछ ऐसा करने के लिए newItem = trueif (newItem ) then
ऑथर

1
@ मेनमा जाहिर तौर पर एक 3 है: 8 बूलियन तर्कों वाला संस्करण वह है जिसके बारे में मैंने तब सोचा जब मैंने "झंडे" पढ़े ...
इजाकाटा

4
क्षमा करें, लेकिन IMHO यह विधि चाइनिंग के लिए एकदम सही मामला है ( en.wikipedia.org/wiki/Method_chaining ), इसके अतिरिक्त, आप एक पैरामीटर ऐरे का उपयोग कर सकते हैं (एक साहचर्य सरणी या मानचित्र होना चाहिए), जहाँ उस पैरामीटर ऐरे में कोई भी प्रविष्टि हो आप उस पैरामीटर के लिए डिफ़ॉल्ट मान व्यवहार का उपयोग करते हैं। अंत में, विधि जंजीर या पैरामीटर सरणियों के माध्यम से कॉल बिट झंडे के रूप में रसीला और अभिव्यंजक हो सकती है, साथ ही, हर भाषा में बिट ऑपरेटर नहीं होते हैं (मैं वास्तव में द्विआधारी झंडे की तरह करता हूं, लेकिन उन तरीकों का उपयोग करूंगा जिनके बारे में मैंने अभी उल्लेख किया है)।
ड्यूकफैगिंग

3
यह बहुत OOP नहीं है, है ना? मैं एक इंटरफ़ेस बनाऊँगा: स्ट्रिंग myNewPassword = makePassword (randomComposeSupplier (नया randomLowerCaseSupplier) (), नया randomUpperCaseSupplier (), नया randomNumberSupplier); स्ट्रिंग MakePassword (आपूर्तिकर्ता <चरित्र> charSupplier) के साथ; और आपूर्तिकर्ता <चरित्र> randomComposeSupplier (आपूर्तिकर्ता <चरित्र> ... आपूर्तिकर्ता); अब आप अपने आपूर्तिकर्ताओं को अन्य कार्यों के लिए फिर से उपयोग कर सकते हैं, उन्हें किसी भी तरह से बना सकते हैं और अपनी जेनप्रासवर्ड विधि को सरल बना सकते हैं ताकि यह न्यूनतम स्थिति में हो।
डिब्बेके

4
@Dibbeke संज्ञा के एक राज्य के बारे में बात करें ...
फिल

15

एक विशाल फ़ंक्शन ब्लॉक गंध है, न कि झंडे। यदि आप ध्वज को पंक्ति 5 पर सेट करते हैं, तो केवल रेखा 354 पर ध्वज की जाँच करें, तो यह बुरा है। यदि आप ध्वज को पंक्ति 8 पर सेट करते हैं और पंक्ति 10 पर ध्वज की जाँच करते हैं, तो यह ठीक है। इसके अलावा, कोड के प्रति ब्लॉक एक या दो झंडे ठीक हैं, एक समारोह में 300 झंडे खराब हैं।


10

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

प्रदर्शन महत्वपूर्ण स्थितियों में अविवेक की लागत सकता है सतह और स्पष्ट झंडे में विखंडन आवश्यक हैं। कहा जा रहा है कि मुझे एक ऐसे मामले को याद करने में परेशानी हो रही है जहाँ मुझे वास्तव में ऐसा करना था।


6

नहीं, झंडे बुरे या बुरे नहीं हैं जिन्हें हर कीमत पर दूर किया जाना चाहिए।

जावा के Pattern.compile (स्ट्रिंग regex, int ध्वज) कॉल पर विचार करें। यह एक पारंपरिक बिटमास्क है और यह काम करता है। जावा में स्थिरांक पर दृष्टि और जहाँ भी आपको 2 एन का एक गुच्छा दिखाई देता है, आप जानते हैं कि वहाँ झंडे हैं।

एक आदर्श रिफैक्टर्ड दुनिया में, एक इसके बजाय एक EnumSet का उपयोग करेगा, जहां स्थिरांक एक एनम में मानों के बजाय होते हैं और जैसा कि प्रलेखन पढ़ता है:

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

एक आदर्श दुनिया में, कि Pattern.compile कॉल बन जाती है Pattern.compile(String regex, EnumSet<PatternFlagEnum> flags)

सभी ने कहा, इसके अभी भी झंडे। यह बहुत आसान है Pattern.compile("foo", Pattern.CASE_INSENSTIVE | Pattern.MULTILINE)कि इसके साथ काम करना आसान होगा Pattern.compile("foo", new PatternFlags().caseInsenstive().multiline())या कुछ और करने की कोशिश होगी जो वास्तव में झंडे हैं और इसके लिए अच्छा है।

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

समस्या तब होती है जब लोग एक साथ झंडे का दुरुपयोग करते हैं और सभी प्रकार के असंबंधित झंडे का फ्रेंकेनफ्लैग सेट बनाते हैं या उनका उपयोग करने की कोशिश करते हैं जहां वे बिल्कुल भी झंडे नहीं होते हैं।


5

मुझे लगता है कि हम विधि हस्ताक्षर के भीतर झंडे के बारे में बात कर रहे हैं।

एकल ध्वज का उपयोग करना काफी खराब है।

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

झंडे को विधि में पास करना, सामान्य रूप से इसका मतलब है कि आपका तरीका कई चीजों के लिए जिम्मेदार है। विधि के अंदर आप शायद इनकी तर्ज पर एक साधारण जाँच कर रहे हैं:

if (flag)
   DoFlagSet();
else
   DoFlagNotSet();

यह चिंताओं का एक अलग अलगाव है और आप आमतौर पर इसके चारों ओर एक रास्ता खोज सकते हैं।

मेरे पास आमतौर पर दो अलग-अलग विधियाँ हैं:

public void DoFlagSet() 
{
}

public void DoFlagNotSet()
{
}

यह विधि के नाम के साथ अधिक समझ में आएगा जो उस समस्या पर लागू होते हैं जिसे आप हल कर रहे हैं।

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


3

झंडे और अधिकांश अस्थायी चर एक मजबूत गंध हैं। सबसे अधिक संभावना है कि उन्हें रिफैक्ट किया जा सकता है और उन्हें क्वेरी विधियों के साथ बदल दिया जा सकता है।

संशोधित:

राज्य को व्यक्त करते समय झंडे और अस्थायी चर, क्वेरी विधियों के लिए फिर से सक्रिय किए जाने चाहिए। राज्य के मान (बूलियन, इन्टस और अन्य प्राइमरी) को लगभग-रेलवे को कार्यान्वयन विवरण के भाग के रूप में छिपाया जाना चाहिए।

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


2

जब हम झंडे के बारे में बात करते हैं तो हमें पता होना चाहिए कि वे कार्यक्रम निष्पादन के समय में संशोधित होने जा रहे हैं और यह कि वे अपने राज्यों के आधार पर कार्यक्रम के व्यवहार को प्रभावित करने जा रहे हैं। जब तक हमारे पास इन दो चीजों पर साफ-सुथरा नियंत्रण है, तब तक वे शानदार काम करेंगे।

झंडे महान काम कर सकते हैं अगर

  • आपने उन्हें एक उपयुक्त दायरे में परिभाषित किया है। उचित रूप से मेरा मतलब है कि स्कोप में कोई भी कोड नहीं होना चाहिए जो उन्हें संशोधित नहीं करना चाहिए। या कम से कम कोड सुरक्षित है (उदाहरण के लिए इसे सीधे बाहर से नहीं बुलाया जा सकता है)
  • अगर बाहर से झंडे को संभालने की जरूरत है और अगर कई झंडे हैं तो हम झंडे को सुरक्षित रूप से संशोधित करने के लिए एक ही रास्ता के रूप में ध्वजवाहक को कोड कर सकते हैं। यह ध्वज हैंडलर स्वयं ही झंडे और तरीकों को संशोधित कर सकता है। इसे तब सिंगलटन बनाया जा सकता है और फिर उन वर्गों के बीच साझा किया जा सकता है जिन्हें झंडे तक पहुंच की आवश्यकता होती है।
  • और अंत में स्थिरता के लिए, अगर बहुत सारे झंडे हैं:
    • यह कहने की आवश्यकता नहीं है कि उन्हें समझदार नामकरण का पालन करना चाहिए
    • मान्य मानों के साथ प्रलेखित किया जाना चाहिए (गणनाओं के साथ हो सकता है)
    • उनमें से प्रत्येक के साथ WHDE CODE WILL MODIFY का दस्तावेजीकरण किया जाना चाहिए, और WHICH CONDITION के साथ ध्वज को एक विशेष मूल्य प्रदान करने का परिणाम होगा।
    • जो कोड उन्हें मिलेंगे और जो एक विशेष मूल्य के लिए परिणाम होगा

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

जब तक ये चीजें लागू होती हैं, मुझे लगता है कि इससे गड़बड़ नहीं होगी।


1

मैंने इस प्रश्न से अनुमान लगाया कि क्यूए का अर्थ था ध्वज (वैश्विक) चर, और फ़ंक्शन पैरामीटर के बिट्स नहीं।

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


0

मुझे नहीं लगता कुछ भी प्रोग्रामिंग में एक पूर्ण बुराई है, कभी भी।

एक और स्थिति है जहां झंडे क्रम में हो सकते हैं, जिनका उल्लेख यहां नहीं किया गया ...

इस जावास्क्रिप्ट स्निपेट में क्लोजर के उपयोग पर विचार करें:

exports.isPostDraft = function ( post, draftTag ) {
  var isDraft = false;
  if (post.tags)
    post.tags.forEach(function(tag){ 
      if (tag === draftTag) isDraft = true;
    });
  return isDraft;
}

"Array.forEach" में पास किया जा रहा आंतरिक फ़ंक्शन, केवल "सही लौटा नहीं सकता"।

इसलिए, आपको एक ध्वज के साथ राज्य को बाहर रखना होगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.