2009-06-28 12 views
13

हाल ही में, मैं एक और प्रोग्रामर के साथ "अगर" बयान से भरे विशाल (1000 लाइनों) विधि को दोबारा करने का सबसे अच्छा तरीका चर्चा कर रहा था।कक्षाओं की श्रृंखला-जिम्मेदारी बनाम सूचियों के फायदे क्या हैं?

कोड जावा में लिखा गया है, लेकिन मुझे लगता है कि यह समस्या सी # जैसी अन्य भाषाओं में भी हो सकती है।

इस समस्या को हल करने के लिए, उन्होंने एक श्रृंखला-जिम्मेदारी पैटर्न का उपयोग करने का सुझाव दिया। उन्होंने आधार "हैंडलर" कक्षा का प्रस्ताव देने का प्रस्ताव रखा। फिर, "हैंडलर 1", "हैंडलर 2" इत्यादि "हैंडलर" का विस्तार करेंगे।
फिर, हैंडलरों के पास "getSuccessor" विधि होगी, जो या तो शून्य (यदि यह श्रृंखला का अंतिम भाग था) या श्रृंखला के अगले हैंडलर को वापस कर देगा।
फिर, "हैंडलआरक्वेट (अनुरोध)" फ़ंक्शन या तो अनुरोध के साथ सौदा करेगा, या इसे श्रृंखला के आगे भेज देगा और यदि पिछले समाधानों में से कोई भी काम नहीं करता है, तो यह केवल शून्य या वापस अपवाद फेंक देगा।
श्रृंखला में एक नया हैंडलर जोड़ने के लिए, कोडर श्रृंखला के अंतिम तत्व पर जायेगा और बताएगा कि एक नया तत्व था। कुछ करने के लिए, वह सिर्फ श्रृंखला के पहले तत्व पर हैंडलरक्वेट को कॉल करेगा।

इस समस्या को हल करने के लिए, मैंने एक अलग दृष्टिकोण का उपयोग करने का सुझाव दिया।
मेरे पास "हैंडलर" कक्षा भी है, जिसमें "हैंडलर 1", "हैंडलर 2", जैसा कि पिछली विधि का उल्लेख किया गया है।
हालांकि, कोई "getSuccessor" विधि नहीं होगी। इसके बजाय, मेरे पास हैंडलर की एक सूची (एक वेक्टर, एक ऐरेलिस्ट, या जो भी इस मामले में सबसे अच्छा है) के साथ एक संग्रह कक्षा होगी।
हैंडलरक्वैस्ट फ़ंक्शन अभी भी मौजूद होगा, लेकिन यह अगले हैंडलरों को कॉल का प्रचार नहीं करेगा। यह सिर्फ अनुरोध को संसाधित करेगा या शून्य वापस करेगा।
एक अनुरोध को पूरा करने के लिए, एक

for(Handler handle : handlers){ 
    result = handle.handleRequest(request); 
    if(result!=null) return result; 
} 
throw new CouldNotParseRequestException(); //just like in the other approach 

का प्रयोग करेंगे या, कोड दोहराव को रोकने के लिए, एक "parseRequest (अनुरोध)" विधि संग्रह वर्ग के लिए जोड़ा जा सकता है। नया हैंडलर जोड़ने के लिए, कोई संग्रह कन्स्ट्रक्टर (या स्थैतिक {} ब्लॉक, या कुछ समकक्ष) पर जायेगा और बस "एडहैंडलर (नया हैंडलर 3()) कोड जोड़ें;"।

इस दृष्टिकोण के साथ मैं वास्तव में क्या जिम्मेदारी का सामना कर रहा हूं? कौन सी विधि सर्वोत्तम है (मान लीजिए एक सर्वोत्तम विधि है)? क्यूं कर? प्रत्येक डिज़ाइन विधि के कारण संभावित बग और समस्याएं क्या हो सकती हैं?

if(x instanceof Type1) 
{ 
//doSomething1 
} else if(x instanceof Type2) 
{ 
//doSomething2 
} 
//etc. 

उत्तर

6

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

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

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

+0

बहुत गहरी रिकर्सन कोई समस्या नहीं होनी चाहिए। यह अपेक्षाकृत छोटा है (सिस्टम ओवरफ्लो ढेर करने के लिए आवश्यक हजारों विधि कॉल के पास कहीं भी नहीं)। – luiscubal

0

नहीं बता सकते हैं कि जवाबदेही की चेन आपका जवाब है, या यहाँ तक GOF लागू होता है अगर:

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

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

दिमाग में 'सबसे आसान चीज संभव' रखें। जटिल तक छलांग न लें जब तक कि आप स्वयं को साबित न करें कि आपको इसकी आवश्यकता है।

मैंने हाल ही में Anti-IF campaign के बारे में पढ़ा है जो इस विचार को बढ़ावा देता है। यहां काफी प्रासंगिक लगता है।

4

कौन सा दृष्टिकोण सबसे अच्छा है कि आपके हैंडलर क्या करना चाहते हैं इस पर निर्भर करता है।

यदि हैंडलर स्वयं अनुरोध अनुरोध पूरी तरह से संभाल सकते हैं, तो आपका दृष्टिकोण ठीक है। हैंडलर के पास अन्य हैंडलर का संदर्भ नहीं है, जो हैंडलर इंटरफ़ेस को सरल बनाता है। जिम्मेदारी की श्रृंखला के मानक कार्यान्वयन के विपरीत, आप श्रृंखला के बीच से हैंडलर जोड़ या निकाल सकते हैं। वास्तव में, आप अनुरोध के प्रकार के आधार पर विभिन्न श्रृंखला बनाने का चयन कर सकते हैं।

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

चूंकि सहकारी में, हैंडलर श्रृंखला पर अगले आइटम का संदर्भ रखता है, तो आप श्रृंखला के बीच से आइटम जोड़ या हटा नहीं सकते हैं। सीओआर की एक भिन्नता जो आपको श्रृंखला के बीच से वस्तुओं को जोड़ने या हटाने की अनुमति देती है वह एक फ़िल्टर चेन है (उदाहरण के लिए, javax.servlet.FilterChain)।

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

"if" कथन को हटाने का एक और तरीका विरासत है। यदि आपके पास कुछ व्यवहार था जो आपको करने की ज़रूरत थी, और वेब सर्वर के लिए एक भिन्नता थी, और SOAP सर्वर के लिए अन्य भिन्नता थी, तो आपके पास WebServerRequestHandler और एक SoapServerRequestHandler हो सकता है, प्रत्येक विस्तार अनुरोध हैन्डलर। विरासत के साथ लाभ तर्क देने के लिए एक स्पष्ट जगह है जो दोनों प्रकार के अनुरोधों के लिए आम है। नुकसान यह है कि चूंकि जावा में एकाधिक विरासत नहीं है, इसलिए आप केवल एकल-आयामी समस्याओं का मॉडल कर सकते हैं।

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