मान लीजिए मैं एक अंतरफलक है कि कुछ संभावित आपरेशन का समर्थन करता है है:वैकल्पिक घटकों के साथ एक इंटरफेस के लिए एक अच्छा डिजाइन क्या है?
interface Frobnicator {
int doFoo(double v);
int doBar();
}
अब, कुछ उदाहरणों केवल एक या इन आपरेशनों के अन्य का समर्थन करेंगे। वे दोनों का समर्थन कर सकते हैं। क्लाइंट कोड तब तक जरूरी नहीं होगा जब तक यह वास्तव में प्रासंगिक कारखाने से निर्भर न हो, निर्भरता इंजेक्शन के माध्यम से, या जहां भी इसे प्राप्त हो रहा हो।
मुझे इसे संभालने के कुछ तरीके दिखाई देते हैं। एक, जो जावा एपीआई में ली गई सामान्य रणनीति प्रतीत होता है, ऊपर दिखाए गए इंटरफ़ेस के पास है और असमर्थित विधियां UnsupportedOperationException
बढ़ाती हैं। हालांकि, यह असफल रहा है, असफल होने के कारण - क्लाइंट कोड यह नहीं बता सकता कि doFoo
doFoo
पर कॉल करने का प्रयास करने तक काम करेगा या नहीं।
इसे supportsFoo()
और supportsBar()
विधियों के साथ बढ़ाया जा सकता है, जो सही do
विधि कार्य करता है तो सही वापस लौटने के लिए परिभाषित किया गया है।
एक और रणनीति doFoo
और doBar
विधियों को FooFrobnicator
और BarFrobnicator
विधियों में क्रमशः कारक करना है। यदि ऑपरेशन असमर्थित है तो ये विधियां null
लौटाएंगी। instanceof
चेकों क्या करने वाले से ग्राहक कोड रखने के लिए, मैं एक Frobnicator
इंटरफेस इस प्रकार निर्धारित करें:
interface Frobnicator {
/* Get a foo frobnicator, returning null if not possible */
FooFrobnicator getFooFrobnicator();
/* Get a bar frobnicator, returning null if not possible */
BarFrobnicator getBarFrobnicator();
}
interface FooFrobnicator {
int doFoo(double v);
}
interface BarFrobnicator {
int doBar();
}
वैकल्पिक रूप से, FooFrobnicator
और BarFrobnicator
Frobnicator
का विस्तार कर सकता है, और get*
तरीकों संभवतः as*
नाम दिया जा।
इसके साथ एक मुद्दा नामकरण है: Frobnicator
वास्तव में एक फ्रोबनिनेटर नहीं है, यह फ्रोबनिकेटर प्राप्त करने का एक तरीका है (जब तक कि मैं as*
नामकरण का उपयोग नहीं करता)। यह भी एक ताकत कमजोर हो जाता है। नामकरण और जटिल हो सकता है, क्योंकि Frobnicator
को FrobnicatorEngine
सेवा से पुनर्प्राप्त किया जाएगा।
क्या किसी को इस समस्या के लिए एक अच्छा, अधिमानतः स्वीकार्य समाधान में कोई अंतर्दृष्टि है? क्या कोई उचित डिजाइन पैटर्न है? विज़िटर इस मामले में उचित नहीं है, क्योंकि क्लाइंट कोड को किसी विशेष प्रकार के इंटरफ़ेस की आवश्यकता होती है (और अगर इसे प्राप्त नहीं किया जा सकता है तो इसे असफल रूप से असफल होना चाहिए), जिस तरह से ऑब्जेक्ट प्राप्त हुआ था, इस पर प्रेषण के विपरीत। या नहीं, विभिन्न सुविधाओं का समर्थन कर रहे चीजों की एक किस्म पर भिन्न हो सकते हैं - Frobnicator
के कार्यान्वयन, कि कार्यान्वयन के रन-टाइम विन्यास (जैसे यह doFoo
ही अगर कुछ सिस्टम सेवा Foo
सक्षम करने के लिए मौजूद है का समर्थन करता है), आदि
अद्यतन: रन-टाइम कॉन्फ़िगरेशन इस व्यवसाय में अन्य बंदर रिंच है। समस्या से बचने के लिए FooFrobnicator और BarFrobnicator प्रकारों को ले जाना संभव हो सकता है, खासकर अगर मैं गिस-मॉड्यूल-ए-कॉन्फ़िगरेशन का हेवर उपयोग करता हूं, लेकिन यह अन्य आसपास के इंटरफेस (जैसे फैक्ट्री/बिल्डर जो फ्रोबनाइनेटर उत्पन्न करता है) में जटिलता पेश करता है पहली जगह में)। असल में, फैब्रिकेटर्स का उत्पादन करने वाले फैक्ट्री के कार्यान्वयन को रन-टाइम (या तो गुणों या एक गुइस मॉड्यूल के माध्यम से) पर कॉन्फ़िगर किया जाता है, और मैं चाहता हूं कि उपयोगकर्ता इसे "इस फ्रोबिनेटर प्रदाता को इस क्लाइंट को हुक अप करें" । मैं मानता हूं कि यह संभावित अंतर्निहित डिज़ाइन समस्याओं के साथ एक समस्या है, और मैं कुछ सामान्यीकरण मुद्दों पर भी विचार कर सकता हूं, लेकिन मैं कम से कम कुरूपता और कम से कम आश्चर्य के संयोजन के लिए जा रहा हूं।
वास्तव में एक तीसरा विकल्प है: 'फ्रोबनिनेटर फूफोबनिनेटर, बारफोबनिनेटर' को बढ़ाता है। एक घटक जो केवल 'FooFrobnicator' है, केवल 'doFoo() 'का समर्थन करेगा, जबकि' BarFrobnicator 'केवल' doBar() 'का समर्थन करेगा। इस के साथ क्या समस्या है? – Riduidel
@ रिडुइडल फिर 'फ्रोबिनेटर' प्रदान करने वाली एक कक्षा है, लेकिन केवल 'डूफू()' का समर्थन करने के लिए 'बारफोबनाइनेटर' को भी लागू करना चाहिए, जो मैंने प्रस्तुत किए गए पहले इंटरफेस में समस्या को कम कर दिया है। मैंने कुछ इंटरफेस को सीधे इस्तेमाल करने की अनुमति देने के लिए प्रकारों को कैसे ले जाना है, इस बारे में कुछ सोचा है, लेकिन यह रन-टाइम कॉन्फ़िगरेशन को एक दुःस्वप्न बनाता है। –