2012-02-21 18 views
5

मैं एक पेज "ReportController.aspx" जिसका उद्देश्य एक रिपोर्ट (वर्ग) क्वेरी स्ट्रिंग के आधार पर का दृष्टांत है पैरामीटरबड़े स्विच के लिए प्रतिस्थापन?

 switch (Request.QueryString["Report"]) 
     {     
      case "ReportA": 
       CreateReportAReport("ReportA's Title"); 
       break; 
      case "ReportB": 
       CreateReportBReport("ReportB's Title"); 
       break;     
      case "ReportC": 
       CreateReportCReport("ReportC's Title"); 
       break; 
      case "ReportD": 
       CreateReportDReport("ReportD's Title"); 
       break; 
       ... 

असल में, हर बार एक नई रिपोर्ट की जरूरत है नामित है जोड़ने की इस भूमि के ऊपर नहीं होगा एक मामला और एक विधि जोड़ना। यह स्विच स्टेटमेंट बहुत लंबा हो सकता है। मैंने पढ़ा है कि एक रिपोर्ट का मानचित्र बनाने के लिए एक शब्दकोश का उपयोग करना संभव है? यह एक शब्दकोश का उपयोग कैसे करेगा (यह मानना ​​कि यह एक बेहतर तरीका है)।

इसके अलावा, CreateReportXReport विधि मूल रूप से रिपोर्ट क्लास के कन्स्ट्रक्टर को अतिरिक्त क्वेरीस्ट्रिंग मानों का एक गुच्छा पास करती है (प्रत्येक रिपोर्ट क्लास में एक अलग कन्स्ट्रक्टर होता है)।

+3

आप मूल्यों को संग्रहीत करने के लिए डेटाबेस का उपयोग करने और एक क्वेरी लिखने पर विचार कर सकते हैं जो आपको चाहिए। तो आपको बस इतना करना है कि प्रत्येक नई रिपोर्ट के साथ डेटा डालें। – northpole

+0

@ नॉर्थपोल - सुनिश्चित नहीं है कि मैं समझता हूं। मान उन पृष्ठों से उपयोगकर्ता चयनों पर आधारित होते हैं जिन्हें ReportController कहा जाता है। –

+0

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

उत्तर

4

यह मानते हुए कि सभी रिपोर्टों IReport लागू, आप इसे Func<IReport> उपयोग कर सकते हैं, इस तरह:

IDictionary<string,Func<IReport>> dictToReport = new Dictionary { 
    {"ReportA",() => CreateReportAReport("ReportA's Title") } 
, {"ReportB",() => CreateReportBReport("ReportB's Title") } 
, ... 
}; 

इसके बाद आप इस कोड के साथ स्विच की जगह ले सकता:

var myReport = dictToReport[Request.QueryString["Report"]](); 
+2

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

+1

@ ब्रोकनग्लस यह रखरखाव के मामले में वास्तव में समान नहीं है, क्योंकि आप कोड को कॉपी-पेस्ट किए बिना जितनी बार चाहें उतनी बार 'IDictionary' का पुन: उपयोग कर सकते हैं। आप 'स्विच' कथन के साथ एक ही काम नहीं कर सकते हैं। आप स्विच करने वाली विधि में स्विच को अलग कर सकते हैं, लेकिन यह लचीला नहीं है। मैं इस बात से सहमत हूं कि यह कारखानों के लिए एक निश्चित समाधान नहीं है। – dasblinkenlight

+0

@dasblinkenlight - क्या आप संकेत दे रहे हैं कि फैक्ट्री विधि पैटर्न इससे भी बेहतर होगा? –

5

कोई चारों ओर हो रही है कहीं नई जानकारी टाइप करने के लिए; इस तरह के मामूली परिवर्तन के लिए पुन: निर्माण और पुनर्वितरण से बचने के लिए, इसे कोड से बाहर निकालना है।

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

आप शायद इस डेटा के साथ एक शब्दकोश, जो कुछ भी स्रोत भरना चाहते हैं। यह इच्छा:

  • आसान कैश करने के लिए
  • स्वच्छ, तेजी से कोड

के लिए सुनिश्चित करें बार कोड में विन्यास में से अपने डेटा खींचने के लिए आता है जब आप करने के लिए आइटम जोड़ना होगा बनाओ, इसलिए जैसे शब्दकोश:

Dictionary<string, IReportCreator> = configDataGetter.GetReportDataFromDB(). 
    ToDictionary(r => r.Name, myReportCreatorFactory(r => r.ReportID)) 

इस उदाहरण मानता है कि repor बनाता है कि अपने कोड के लिए एक strategy pattern का प्रयोग करेंगे किसी तरह की इकाई वस्तु, और एक कारखाने का उपयोग कर के रूप में अपने हो रही डेटा ts। निश्चित रूप से ऐसा करने के लिए एक अरब तरीके हैं।

मुझे लगता है कि रिपोर्ट प्रकृति में बहुत व्यापक, विविध और अलग हैं कि आप डीबी में एसक्यूएल और स्टाइल बिल्डिंग ब्लॉक नहीं डाल सकते हैं?

संपादित सेशन की टिप्पणी के आधार:

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

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

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

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

इस बिंदु पर, एक नई रिपोर्ट जोड़ने का तरीका बहुत साफ है, भले ही आपको हर बार एक नई कक्षा जोड़नी पड़े। उतना अच्छा। यह single responsibility और open-closed प्रिंसिपल को पूरा करता है।

अब, का अंतिम चरण केवल आपके ऐप से कक्षाओं को हटा रहा है, इसलिए उन्हें फ्लाई पर जोड़ा/संपादित किया जा सकता है। MEF देखें। यही वह है जो इसके लिए बनाया गया है। इंटरनेट पर आपको कुछ चीजें मिल सकती हैं जो आपको शायद उपयोग नहीं करनी चाहिए CodeDom (जब कुछ और नहीं था, लेकिन एमईएफ बेहतर है) और .NET 5. MEF में आने वाली संकलन-जैसी-सेवा सुविधाएं हैं। जाने का रास्ता।

+0

दाएं। जावा के लिए, यही कारण है कि आप स्प्रिंग फ्रेमवर्क जैसी चीजें देखेंगे। इस तरह आप केवल एक सामान्य फैक्ट्री ऑब्जेक्ट या डिक्शनरी का संदर्भ दे सकते हैं। आपका कोड केवल ReportFactory.create (Request.QueryString ["रिपोर्ट"] पर कॉल करता है), और तर्क आपके वर्ग के बाहर बनाए रखा जाता है, जिससे इसे कम जटिल बना दिया जाता है। –

+0

@ पैट्रिककारर - प्रत्येक रिपोर्ट क्लास अपने कन्स्ट्रक्टर में पैरामीटर की एक सूची में ले जाती है (ऊपर दिखाया नहीं गया है)। मुझे अभी भी सर्वर पर नई फ़ाइल (रिपोर्ट) को तैनात करना होगा, पैरामीटर और रिपोर्ट नाम इसका एक हिस्सा हैं। इसमें एक पूरी नई कक्षा शामिल है। –

+0

@ पैट्रिककारर - शायद भविष्य में मैं इस तरह से लागू करूंगा, लेकिन मुझे अभी तक समझ में नहीं आता है। –

1

मुझे लगता है कि इस कोड को फिर से डिजाइन करना बेहतर है और प्रत्येक रिपोर्ट की रिपोर्ट और आईडी की सूची रखने के लिए इसे कुछ डेटाबेस तालिका ("रिपोर्ट्स") में परिवर्तित करें।

यही है।

+0

हां, मैं ऐसा कर सकता था, लेकिन मुझे क्वेरीस्ट्रिंग से रिपोर्ट क्लास में उचित उपयोगकर्ता चयन पास करने के लिए, डेटाबेस से इसे पढ़ने के बाद भी रिपोर्ट पर स्विच करना होगा। मैं नहीं देखता कि यह कैसे बेहतर होगा। –

+1

@ subt13 यह ठीक है। आप किसी भी शब्दकोश को रखने के लिए सत्र/कैश का उपयोग करने का प्रयास कर सकते हैं। तो केवल एक बार रिपोर्ट की सूची के साथ इस शब्दकोश सत्र सत्र में जोड़ें। –

+0

आप शायद सही हैं, मुझे लगता है कि मैं इसे लागू करने के लिए पर्याप्त समझ में नहीं आता हूं। –

1

एक Dictionary<string, string> साथ ऐसा करने के लिए आप बस युक्त प्रकार

public class Container { 
    private static Dictionary<string, Func<Report>> ReportMap = 
    new Dictionary<string, Func<Report>>(); 
    static Container() { 
    ReportMap["ReportA"] =() => CreateReportAReport("ReportA's Title"); 
    ReportMap["ReportB"] =() => CreateReportBReport("ReportB's Title"); 
    // etc ... 
    } 
} 

अब में एक स्थिर कैश कि नक्शा बनाया गया है तो आप बस एक switch

के बजाय समारोह में एक देखने कर के रूप में एक का निर्माण होगा
Func<Report> func; 
if (!ReportMap.TryGetValue(Request.QueryString["Report"), out func)) { 
    // Handle it not being present 
    throw new Exception(..); 
} 

Report report = func(); 
+0

+1 क्या यह एक "फैक्टरी विधि पैटर्न" है? –

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