2015-02-18 5 views
6

मैं एक प्रकार के गणित के साथ निपटने के लिए एक अच्छा, साफ डिज़ाइन पैटर्न या सामान्य रूप से स्वीकृत कार्यान्वयन खोजने की कोशिश कर रहा हूं जहां व्यक्तिगत प्रकार केवल रनटाइम पर जाना जाता है।प्रकार पैटर्न पर स्विचिंग से बचने के लिए डिज़ाइन पैटर्न या स्वीकृत समाधान

मुझे पता है कि पहले से ही इसी तरह के प्रश्न पूछे गए हैं, लेकिन यह अभी भी मुझे स्पष्ट नहीं है कि वैकल्पिक कार्यान्वयन के स्विच पर महत्वपूर्ण फायदे हैं, या if-thens की श्रृंखला है।

सबसे पहले, मैं कुछ कार्यान्वयन का प्रदर्शन करने जा रहा हूं, और फिर मैं सवाल पूछने जा रहा हूं: क्या ये कार्यान्वयन सरल स्विच से बेहतर या पसंदीदा हैं? यदि हां, तो क्यों? यदि नहीं, तो क्यों नहीं?

मेरे आवेदन में मैं एक स्ट्रीम पर डेटा भेजता हूं और प्राप्त करता हूं। रन टाइम पर, मुझे धारावाहिकरण के माध्यम से एक डेटा संरचना प्राप्त होती है जो बताती है कि मेरे बाइनरी डेटा के भीतर कौन से फ़ील्ड स्थित हैं। इसमें फ़ील्ड में डेटा का प्रकार शामिल है, यानी इंट 32, बूल, डबल इत्यादि। डिजाइन समय पर, मुझे पता है कि डेटा कई प्रकारों में से एक में हो सकता है। मुझे स्ट्रीम से फ़ील्ड पढ़ने और उचित तरीके से डेटा से निपटने की जरूरत है।

गैर काम कोड::

हैं प्रकार चालू करने की अनुमति दी गई, एक समाधान इस प्रकार हो सकता है

object ReadDataField(byte [] buff, ref int position, 
    Dictionary<int, Type> fields) 
{ 
    object value; 
    int field = buff[position]; 
    position++; 

    switch(fields[field]) 
    { 
     case typeof(Int32): 
     { 
      value = (Int32)BitConverter.ToInt32(buff, position); 
      position += sizeof(Int32); 
      break; 
     } 
     case typeof(Int16): 
     { 
      value = (Int16)BitConverter.ToInt16(buff, position); 
      position += sizeof(Int16); 
      break; 
     } 
     // Etc... 
    } 

    return value; 
} 

मेरी राय में, इस कोड को सीधा किया जा रहा है का लाभ दिया है , पढ़ने के लिए आसान, और बनाए रखने के लिए सरल है।

कार्य कोड::

लेकिन, जैसा कि प्रकार स्विच ऑन करने के सी # में उपलब्ध नहीं है मैं ऊपर इस प्रकार के रूप में लागू

enum RawDataTypes 
{ 
    Int32, 
    Int16, 
    Double, 
    Single, 
    etc. 
} 

object ReadDataField(byte [] buff, ref int position, 
    Dictionary<int, RawDataTypes> fields) 
{ 
    object value; 
    int field = buff[position]; 
    position++; 

    switch(fields[field]) 
    { 
     case RawDataTypes.Int32: 
     { 
      value = (int)BitConverter.ToInt32(buff, position); 
      position += sizeof(int); 
      break; 
     } 
     case RawDataTypes.Int16: 
     { 
      value = (Int16)BitConverter.ToInt16(buff, position); 
      position += sizeof(Int16); 
      break; 
     } 
     // Etc. 
    } 

    return value; 
} 

यह स्पष्ट रूप से एक काम के आसपास है, लेकिन यह भी है सीधा और बनाए रखने में आसान है।

हालांकि, सी # में प्रकारों पर स्विचिंग का विवरण देने वाले कई लेख हैं। और विरासत से निपटने में कठिनाई के अलावा, जो अपेक्षित परिणाम उत्पन्न करता है, आदि, मैंने कई उत्तरों को देखा है, जिन्होंने कहा है कि "बेहतर" दृष्टिकोण है जो ऑब्जेक्ट उन्मुख प्रोग्रामिंग की भावना के अनुरूप है।

प्रस्तावित सामान्य समाधान 1) पॉलिमॉर्फिज्म का उपयोग करें, या 2) एक शब्दकोश लुकअप का उपयोग करें। लेकिन कार्यान्वयन या तो अपनी चुनौतियों का सामना करना पड़ता है।

गैर काम बहुरूपता का कार्यान्वयन:

object ReadDataField(byte [] buff, int position, 
    Dictionary<int, Type> fields) 
{ 
    int field = buff[position]; 
    position++; 

    object value = Activator.CreateInstance(fields[field]); 
    // Here we're trying to use an extension method on the raw data type. 
    value.ReadRawData(buff, ref position); 

    return value; 
} 

public static Int32 ReadRawData(this Int32 value, byte[] buff, ref int position) 
{ 
    value = BitConverter.ToInt32(buff, position); 
    position += sizeof(Int32); 

    return value; 
} 

public static Int16 ReadRawData(this Int16 value, byte[] buff, ref int position) 
{ 
    value = BitConverter.ToInt16 (buff, position); 
    position += sizeof(Int16); 

    return value; 
} 

// Additional methods for each type... 

आप करने की कोशिश

बहुरूपता के बारे में, निम्न में से कोई एक उदाहरण "यह अच्छा नहीं होगा अगर यह काम किया" कोड है ऊपर दिए गए कोड को संकलित आप प्राप्त करेंगे:

'वस्तु' 'ReadRawData' के लिए एक परिभाषा और सबसे अच्छा विस्तार विधि अधिभार 'RawDataFieldExt शामिल नहीं है ensions.ReadRawData (लघु, बाइट [], ref int) 'blah blah में कुछ अवैध तर्क है ...

आप कार्यक्षमता जोड़ने के लिए कच्चे डेटा प्रकारों को उपclass नहीं कर सकते हैं, क्योंकि वे सील कर रहे हैं, इसलिए विस्तार विधियां एक विकल्प की तरह लगती हैं। हालांकि, एक्सटेंशन ऑब्जेक्ट्स 'ऑब्जेक्ट' से वास्तविक प्रकार में परिवर्तित नहीं होंगे, भले ही कॉलिंग वैल्यू हो। GetType() अंतर्निहित प्रकार देता है: System.Int32, System.Int16, आदि 'गतिशील' कीवर्ड का उपयोग नहीं करता है मदद, या तो, क्योंकि you can't use extension methods on a dynamic type

बहुरूपता का कार्य कार्यान्वयन::

object ReadDataField(byte [] buff, int position, 
    Dictionary<int, Type> fields) 
{ 
    int field = buff[position]; 
    position++; 

    dynamic value = Activator.CreateInstance(fields[field]); 
    // Here the object is passed to an overloaded method. 
    value = ReadRawData(value, buff, ref position); 

    return value; 
} 

public static Int32 ReadRawData(Int32 value, byte[] buff, ref int position) 
{ 
    value = BitConverter.ToInt32(buff, position); 
    position += sizeof(Int32); 

    return value; 
} 

public static Int16 ReadRawData(Int16 value, byte[] buff, ref int position) 
{ 
    value = BitConverter.ToInt16 (buff, position); 
    position += sizeof(Int16); 

    return value; 
} 

// Additional methods for each type... 

ऊपर

ऊपर बहुरूपी मानकों के साथ तरीकों की एक पैरामीटर के रूप वस्तु ही का एक उदाहरण पारित करके काम करने के लिए बनाया जा सकता है कोड काम करता है और अभी भी सरल और रखरखाव योग्य है, और शायद "ऑब्जेक्ट उन्मुख प्रोग्रामिंग की भावना में"।

लेकिन क्या यह वास्तव में कोई "बेहतर है?" मैं तर्क दूंगा कि यह और बनाए रखने में मुश्किल है, क्योंकि इसे देखने के लिए और अधिक खोज की आवश्यकता है कि किस प्रकार को लागू किया गया है।

एक वैकल्पिक दृष्टिकोण एक शब्दकोश लुकअप का उपयोग करना है। इस तरह के कोड इस प्रकार दिखाई देंगे:

शब्दकोश कार्यान्वयन:

delegate object ReadDelegate(byte [] buff, ref int position); 

static Dictionary<Type, ReadDelegate> readers = new Dictionary<Type, ReadDelegate> 
{ 
    { typeof(Int32), ReadInt32 }, 
    { typeof(Int16), ReadInt16 }, 
    // Etc... 
}; 

object ReadDataField(byte [] buff, int position, 
    Dictionary<int, Type> fields) 
{ 
    int field = buff[position]; 
    position++; 

    object value = readers[fields[field]](buff, ref position); 

    return value; 
} 

public static object ReadInt32(byte[] buff, ref int position) 
{ 
    Int32 value = BitConverter.ToInt32(buff, position); 
    position += sizeof(Int32); 

    return value; 
} 

public static object ReadInt16(byte[] buff, ref int position) 
{ 
    return BitConverter.ToInt16(buff, position); 
    position += sizeof(Int16); 

    return value; 
} 

// Additional methods for each type... 

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

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

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

+0

पवित्र धूम्रपान, यह एक व्यापक रूप से लिखित प्रश्न है। हां, पॉलिमॉर्फिज्म प्रकारों पर स्विच करने, विशिष्ट प्रकारों की जांच आदि से बचने का सामान्य तरीका है। कृपया प्रश्न को संकीर्ण करें ताकि इसका उत्तर एक विशिष्ट, स्पष्ट तरीके से दिया जा सके। Http://stackoverflow.com/help/how-to-ask –

+2

मुझे कहानियों की तरह वर्णित प्रश्न पसंद हैं :) यह पूरी सोच प्रक्रिया प्रस्तुत करता है और सभी संभावनाओं के माध्यम से आगे बढ़ता है। बस मेरा विचार – Fka

+0

@ पीटर ड्यूनिहो, मैं थोड़ा सा संकुचित करने के लिए अपने प्रश्न को फिर से लिखता हूं। हालांकि, मैं कई कार्यान्वयन उदाहरणों और उनके पीछे सोच को शामिल करना चाहता था। – tfjield

उत्तर

3
  1. 'कन्वर्टर्स' (या जो कुछ भी) का एक स्थिर संग्रह का उपयोग करें जो सभी एक सामान्य इंटरफेस को लागू करते हैं। फिर आप उस संग्रह को फिर से भर सकते हैं यदि वे इस प्रकार को संभालते हैं। अगर वे करते हैं, तो उन्हें ऐसा करने के लिए कहें। प्रत्येक कनवर्टर केवल इसके प्रकार के बारे में जानता है।
  2. कन्वर्टर्स के समान स्थिर 'संग्रह' का उपयोग करें, लेकिन उन्हें टाइप करके कुंजीपटल में रखें। फिर कनवर्टर से शब्दकोश से टाइप करें और इसे आपके लिए कनवर्ट करने के लिए कहें। (एक आम इंटरफेस के साथ) कि विभिन्न परिवर्तित एल्गोरिदम संपुटित

    अलग कनवर्टर वस्तुओं को परिभाषित करें:

+2

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

+0

हां, 'कनवर्टर' के उदाहरण के बजाय एक प्रतिनिधि एक दिलचस्प विचार है जिसे मैंने नहीं माना। यह कुछ ऐसा है जो मैं कहीं और उपयोग करने में सक्षम हो सकता हूं। @ पीटर श्नाइडर के विचार के लिए धन्यवाद। –

+0

आपके इनपुट, दोस्तों के लिए धन्यवाद। मेरे सर्वोत्तम अनुमान में, मैंने उपरोक्त मेरे प्रश्न में आपके विचारों को शामिल किया है। सबसे पहले, क्या मैं आप जो सुझाव दे रहा हूं उसे कैप्चर कर रहा हूं? और दूसरा, यदि मैं हूं, तो आपकी राय में, यह सरल सशर्तताओं से बेहतर बनाता है? @PeterSchneider, एक स्विच_ की _readability और रखरखाव के बारे में आपकी टिप्पणियां और "जैसे ही आप एक _second_ स्विच प्रोग्राम करते हैं, अब डेटा में जानकारी संग्रहीत करने का समय है" मुझे लगता है! :) – tfjield

0

Strategy डिजाइन पैटर्न का उपयोग करें। ग्राहक रन-टाइम पर उचित कनवर्टर ऑब्जेक्ट में कनवर्ट करने का प्रतिनिधि करते हैं।

यह कार्यान्वयन निर्भरताओं को बहुत कम करता है। क्लाइंट कोड परिवर्तित है कि कनवर्टिंग कैसे कार्यान्वित किया जाता है।

मैं @ डेविड ओसबोर्न के उत्तर से सहमत हूं। और यहां तक ​​कि यदि आप एक स्विच कथन के साथ एक कनवर्टर ऑब्जेक्ट को लागू करते हैं, यह कार्यान्वयन ग्राहकों से encapsulated और छुपा हुआ है।

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