2015-04-30 7 views
6

समान पैरामीटर के साथ विभिन्न कार्यों के लिए पूर्व शर्त लिखते समय, मैं स्पष्ट रूप से लिखने के बजाय, एक स्थैतिक विधि में दावे या अपवादों को समूहबद्ध करना चाहता हूं। उदाहरण के लिए,DRY रहने के लिए स्वीकार्य विधि में पूर्व शर्त समूहबद्ध कर रहा है?

GetFooForUser(User user) 
{ 
    assert(null != user); 
    assert(user.ID > 0); // db ids always start at 1 
    assert(something else that defines a valid user); 
    ... 

    // do some foo work 
} 

GetBarForUser(User user) 
{ 
    assert(null != user); 
    assert(user.ID > 0); // db ids always start at 1 
    assert(something else that defines a valid user); 
    ... 

    // do some bar work 
} 

के बजाय के लिए मैं लिखने के लिए

GetFooForUser(User user) 
{ 
    CheckUserIsValid(user); 

    // do some foo work 
} 

GetBarForUser(User user) 
{ 
    CheckUserIsValid(user); 

    // do some bar work 
} 

static CheckUserIsValid(User user) 
{ 
    assert(null != user); 
    assert(user.ID > 0); // db ids always start at 1 
    assert(something else that defines a valid user); 
    ... 
} 

यह और अधिक प्राकृतिक लगता है और नीचे कोड मैं (लिखने की ज़रूरत और यहां तक ​​कि मेरे कथनों में त्रुटियों की संख्या कम हो सकता कटौती में मदद करता है पसंद करेंगे !) लेकिन ऐसा लगता है कि पूर्व शर्त को विधि के सही इरादे को दस्तावेज में मदद करनी चाहिए।

क्या यह एक आम विरोधी पैटर्न है या ऐसा करने के लिए कोई महत्वपूर्ण कारण नहीं हैं?

इसके अलावा, अगर मैं अपवादों का उपयोग करता तो उत्तर अलग होगा?

+0

मैंने एक निश्चित उत्तर जोड़ा। –

+0

मेरे लिए, प्राथमिक अंतर पूर्व शर्त जांच का दायरा होगा। इस मामले में (क्योंकि यह एक जटिल व्यापार नियम है - "कुछ और जो वैध उपयोगकर्ता को परिभाषित करता है" - चेक किया जा रहा है) मुझे 'लपेटा/सहायक' चेक पर कोई आपत्ति नहीं होगी। हालांकि, मैं शायद अलग से शून्य की जांच करूँगा। – user2864740

+0

@ user2864740 आप अलग से शून्य की जांच क्यों करेंगे? मेरे पास कई समूहबद्ध चेक हैं जिनके लिए पहले चरण के रूप में शून्य जांच की आवश्यकता है। –

उत्तर

2

ठोस जवाब

यह पूरी तरह स्वीकार्य है: नेट स्रोत कोड की स्थिति गिर्द घूमती है।

उदाहरण के लिए, StringBuilder source code में VerifyClassInvariant() नामक एक विधि है जिसे यह 18 बार कॉल करता है। विधि सिर्फ शुद्धता की जांच करता है।

private void VerifyClassInvariant() 
{  
    BCLDebug.Correctness((uint)(m_ChunkOffset + m_ChunkChars.Length) >= m_ChunkOffset, "Integer Overflow"); 
    StringBuilder currentBlock = this; 
    int maxCapacity = this.m_MaxCapacity; 
    for (; ;) 
    { 
     // All blocks have copy of the maxCapacity. 
     Contract.Assert(currentBlock.m_MaxCapacity == maxCapacity, "Bad maxCapacity"); 
     Contract.Assert(currentBlock.m_ChunkChars != null, "Empty Buffer"); 

     Contract.Assert(currentBlock.m_ChunkLength <= currentBlock.m_ChunkChars.Length, "Out of range length"); 
     Contract.Assert(currentBlock.m_ChunkLength >= 0, "Negative length"); 
     Contract.Assert(currentBlock.m_ChunkOffset >= 0, "Negative offset"); 

     StringBuilder prevBlock = currentBlock.m_ChunkPrevious; 
     if (prevBlock == null) 
     { 
      Contract.Assert(currentBlock.m_ChunkOffset == 0, "First chunk's offset is not 0"); 
      break; 
     } 
     // There are no gaps in the blocks. 
     Contract.Assert(currentBlock.m_ChunkOffset == prevBlock.m_ChunkOffset + prevBlock.m_ChunkLength, "There is a gap between chunks!"); 
     currentBlock = prevBlock; 
    } 
} 

संवाद

यह समूह दावे या अपवाद के लिए ठीक एक स्थिर विधि में, बल्कि उन्हें बाहर लेखन स्पष्ट रूप से है?

हां। ठीक है।

... ऐसा लगता है कि पूर्व शर्त को किसी विधि के सटीक उद्देश्य को दस्तावेज़ में मदद करने में मदद करनी चाहिए।

विधि है कि assert या Exception बयान लपेटता के नाम आवरण के इरादे से संवाद करना चाहिए। इसके अलावा, अगर पाठक विनिर्देशों को जानना चाहता है, तो वह विधि के कार्यान्वयन को देख सकती है (जब तक कि यह बंद स्रोत न हो।)

क्या यह अच्छा या बुरा अभ्यास माना जाता है, और क्यों?

यह का एक सेट रैप करने के लिए अच्छा व्यवहार है संबंधित या आम तौर पर किसी अन्य विधि में asserts पुन: उपयोग किया, क्योंकि यह दोनों पठनीयता में सुधार और रखरखाव की सुविधा कर सकते हैं।

क्या यह एक आम विरोधी पैटर्न है?

इसके विपरीत, वास्तव में। आप ऐसा कुछ देख सकते हैं और यह वास्तव में सहायक और अनुशंसित है क्योंकि यह अच्छी तरह से संवाद करता है।

private void IfNotValidInputForPaymentFormThenThrow(string input) 
{ 
    if(input.Length < 10 || input.Length) 
    { 
     throw new ArgumentException("Wrong length"); 
    } 

    // other conditions omitted 
} 

यह इतना है कि फोन करने वाले को जानता है आप मना रहे हैं विधि के अंत तक ThenThrow जोड़ने के लिए एक अच्छा विचार है। अन्यथा, आप bool वापस लौटना चाहेंगे और कॉलर को यह तय करने दें कि स्थिति विफल होने पर क्या करना है।

private bool IsValidInputForPaymentForm(string input) 
{ 
    if(input.Length < 10 || input.Length) 
    { 
     return true; 
    } 
    else 
    { 
     return false; 
    } 

    // other conditions omitted 
} 

फिर बुला कोड फेंक कर सकते हैं:

if(!IsValidInputForPaymentForm(someStringInput) 
{ 
    throw new ArgumentException(); 
} 

या, यहाँ another example from the .NET source कि एक अपवाद फेंकता है तो कुछ शर्तें असफल है

// Allow nulls for reference types and Nullable<U>, 
// but not for value types. 
internal static void IfNullAndNullsAreIllegalThenThrow<T>(
    object value, ExceptionArgument argName) 
{ 
    // Note that default(T) is not equal to null 
    // for value types except when T is Nullable<U>. 
    if (value == null && !(default(T) == null)) 
     ThrowHelper.ThrowArgumentNullException(argName); 
} 
( ThrowHelper सिर्फ अपवाद फेंकता है।)

क्या ऐसा करने के लिए कोई महत्वपूर्ण कारण नहीं है?

मैं की है कि क्या सोच सकते हैं, अगर विधि नाम आप क्या जाँच कर रहे हैं की व्याख्या नहीं करता है, और वहाँ स्रोत देखने के लिए, तो आप शायद स्थिति लपेटकर से बचना चाहिए एक आसान तरीका नहीं है।

+0

मैंने अपने प्रश्न को थोड़ा कम राय-आधारित होने के लिए अपडेट किया है। नामकरण के बारे में आपका मुद्दा शायद मेरे लिए निर्णायक कारक होगा। जब मैं पूरे समूह के इरादे को नाम में व्यक्त किया जा सकता हूं तो मैं इसे स्वीकार्य मानूंगा। –

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