2011-12-21 13 views
5

यह प्रश्न शायद पहले पोस्ट किया गया है, लेकिन मुझे यह नहीं मिला।इंटरफ़ेस या स्विच स्टेटमेंट, सही पैटर्न ढूंढना

मैं इतने लंबे समय के लिए बात की इस तरह लिख रहा है, मैं बैठ जाओ कुछ नया लिखने के लिए और सिर्फ अगर यह अपने ही पैटर्न थे के रूप में इस लिखना प्रारंभ करें। एक परियोजना हाल ही में आई और मैंने खुद को अपने कोड को देखकर पाया कि यह कितना सुगंधित दिख रहा है।

BackgroundInfoIfYouCare 

इस विशेष पुस्तकालय में मुझे उपयोगकर्ताओं को ईमेल भेजने की आवश्यकता है। अभी तक 13 डिब्बाबंद ईमेल हैं।

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

मेरे पास एक कक्षा है जो एक ईमेल टेम्पलेट नाम कुंजी है जो एक स्ट्रिंग स्वीकार करता है।

विधि उचित क्वेरी चलाएगी और एक सूची वापस ले जाएगी, ईमेल टेम्पलेट पकड़ लेता है।

सूची और टेम्पलेट एक पार्सर के लिए पारित करने के लिए टेम्पलेट की सदस्यता से प्रत्येक मर्ज करने के लिए और एक सूची ईमेल ढूंढ कर रहे हैं।

EndOfBackgroundInfoIfYouCare 

तो असली सवाल ... ऐसा करने का सबसे अच्छा तरीका क्या है?

एक तरह से बस एक स्विच

public List<Membership> Execute(string TemplateKey) { 
switch (TemplateKey) 
     { 
      case "SomethingExpired": 
       QueryResult = new SomethingExpiredEmailQuery().ExecuteQuery(); 
       break; 
      case "SomethingExpireIn30": 
       QueryResult = new SomethingExpireIn30EmailQuery().ExecuteQuery(); 
       break; 
      case "FirstTimeLoginThanks": 
       QueryResult = new FirstTimeLoginThanksEmailQuery().ExecuteQuery(); 
       break; 
      case "SecurityTraining": 
       QueryResult = new SecurityTrainingEmailQuery().ExecuteQuery(); 
       break; 
      case ETC ETC ETC... 

}

एक और तरीका है एक अंतरफलक

IEmailQuery 
void ExecuteQuery() 

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

प्रतिबिंब के साथ मैं नाम की तरह कुछ कर सकता है एक पैटर्न के साथ ईमेल सभी जिज्ञासाओं के: SecurityTraining की ईमेल टेम्पलेट कुंजी SecurityTrainingEmailQuery के एक प्रश्न का नाम है और मैं प्रतिबिंब इस्तेमाल कर सकते हैं का दृष्टांत और ExecuteQuery विधि कॉल करने के।

प्रतिबिंब का उपयोग किए बिना, क्या इसे तारों का कोई क्लीनर तरीका नहीं है?

उत्तर

3

दरअसल, यह मेरे लिए बहुत गंध नहीं लग रहा है। यदि आपको स्विच-कथन पसंद नहीं है तो आप IEmailQuery-Path पर जा सकते हैं और इसे Dictionary<string,IEmailQuery> में बस तार कर सकते हैं। यह शायद, कोड की कुछ पंक्तियाँ की बचत होती है तो आप इसे ऐसे ही यहां पहुंच सकता है के रूप में:

QueryDictionary["MyKey"].ExecuteQuery(); 

चीयर्स, ओलिवर

+0

खैर, जॉन का जवाब समान है, केवल एक और तरीका उन्नत है तो मेरा डर है ;-) – Lindan

7

एक विकल्प Dictionary<string, Func<IEmailQuery>> मानचित्र है। आप इसे इस तरह बना सकते हैं:

private static readonly Dictionary<string, Func<IEmailQuery>> MailQueryMap = 
    new Dictionary<string, Func<IEmailQuery>> { 
    { "SomethingExpired",() => new SomethingExpiredMailQuery() }, 
    { "SomethingExpireIn30",() => new SomethingExpireIn30EmailQuery() }, 
    // etc 
}; 

तब:

public List<Membership> Execute(string templateKey) { 
    IEmailQuery query = MailQueryMap[templateKey].Invoke(); 
    var queryResult = query.ExecuteQuery(); 
    // ... 
} 

आप कर सकते हैं गारंटी है कि आप केवल कभी parameterless कंस्ट्रक्टर्स जरूरत है, तो आप हमेशा एक Dictionary<string, Type> की दुकान और प्रतिबिंब के माध्यम से यह दृष्टांत सकता है - लेकिन कुछ बदसूरत जानवरों आदि होंगे

संपादित करें: बेशक, यदि टेम्पलेट का नाम हमेशा है प्रकार का नाम है, तो आप इस्तेमाल कर सकते हैं

Type queryType = Type.GetType(namespacePrefix + "." + templateKey); 
IEmailQuery query = (IEmailQuery) Activator.CreateInstance(queryType); 
var queryResult = query.ExecuteQuery(); 

तुम भी करने के लिए जादू के बजाय एक enum उपयोग करने पर विचार चाहते हो सकता है स्ट्रिंग स्थिरांक।

+0

यह कैसे खुला/बंद सिद्धांत का पालन करता है? अगर मैंने पॉल की पोस्ट सही ढंग से पढ़ी है तो वह मौजूदा वर्गों को बदलने से बचाना चाहता है (नए मामलों के साथ स्विच स्टेटमेंट बढ़ा रहा है)। – Wivani

+0

@ विवाणी: मुझे यह सुझाव देने वाला कुछ भी नहीं देखा - मैंने केवल देखा कि वह चाहता है कि कोड बनाए रखना आसान और आसान हो। प्रश्न में कहां मौजूदा वर्गों को बदलने से बचने के बारे में बात करते हैं? –

+0

मान लीजिए कि मैं 'आप और मेरे बाहर एक गधे' बना रहा हूं ;-) चलिए देखते हैं कि पॉल क्या पुष्टि कर सकता है कि वह क्या सोच रहा है। – Wivani

0

आपके प्रश्न में प्रस्तावित प्रतिबिंब का उपयोग क्यों नहीं करते? मुझे लगता है कि यह इस तरह की चीजें करने का एक वैध तरीका है।

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

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

YourIocContainer.Register<IEmailQuery>(typeof(SomethingExpiredMailQuery), 
             "SomethingExpiredMailQuery"); 

जब instantiating, आप सेवा का नाम फिर से आपूर्ति करके इसी कार्यान्वयन प्राप्त कर सकते हैं:

public List<Membership> Execute(string TemplateKey) { 
    YourIocContainer.Resolve<IEmailQuery>(TemplateKey); 
+0

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

1

मैं, कुछ की तरह

class EmailQueryFactory 
{ 
    public IEmailQuery Create(String TemplateKey) 
    { 
    .... 
    } 
} 

और फिर एक फैक्टरी पैटर्न के लिए जाना चाहते हैं

//.. first get String TemplateKey 

IEmailQuery qry=EmailQueryFactory.Create(TemplateKey); 
qry.Execute(); 
+0

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

0

कमांड पैटर्न इस परिदृश्य के लिए उपयोग करने के लिए एक आदर्श पैटर्न है। इस पैटर्न के अभ्यास सी # विवरण के लिए http://www.codeproject.com/KB/books/DesignPatterns.aspx देखें। जॉन स्कीट के रूप में लैम्बडास ने वर्णित उपयोगी प्रोग्रामिंग संरचनाएं हैं जिन्हें आप देख सकते हैं। पैटर्न के उपयोग पर अधिक चर्चा के लिए Command Pattern : How to pass parameters to a command? देखें।

+0

कमांड पैटर्न का उल्लेख करने के लिए धन्यवाद। मुझे 4gang पुस्तक से परिभाषा को फिर से पढ़ने के लिए मजबूर किया। मैं उत्सुक हूं कि इसके उपयोग के द्वारा मुझे क्या हासिल होगा। क्या मुझे अभी भी आदेश देने के लिए रिसीवर का एक उदाहरण बनाने की आवश्यकता नहीं होगी? मुझे कक्षाओं की एक सूची में वापस लाता है और एक अनुरोधित आदेश को सही से जोड़ता है। –

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