वास्तविक दुनिया - लिस्कोव प्रतिस्थापन सिद्धांत


14

बैकग्राउंड: मैं एक मैसेजिंग फ्रेमवर्क विकसित कर रहा हूं। यह ढांचा अनुमति देगा:

  • सेवा बस पर संदेश भेजना
  • संदेश बस में कतारों की सदस्यता लेना
  • संदेश बस में विषयों की सदस्यता लेना

हम वर्तमान में RabbitMQ का उपयोग कर रहे हैं, लेकिन मुझे पता है कि हम निकट भविष्य में Microsoft सेवा बस (परिसर में) पर जा रहे हैं।

मैं इंटरफेस और कार्यान्वयन का एक सेट बनाने की योजना बना रहा हूं ताकि जब हम सर्विसबस में जाएं, तो मुझे बस क्लाइंट कोड (अर्थात प्रकाशक या ग्राहक) में संशोधन किए बिना एक नया कार्यान्वयन प्रदान करना होगा।

यहाँ मुद्दा यह है कि RabbitMQ और ServiceBus सीधे अनुवाद योग्य नहीं हैं। उदाहरण के लिए, RabbitMQ एक्सचेंजों और टॉपिक नामों पर निर्भर करता है, जबकि सर्विसबस सभी नामस्थानों और क्वीन्स के बारे में है। इसके अलावा, ServiceBus क्लाइंट और RabbitMQ क्लाइंट के बीच कोई आम इंटरफेस नहीं है (उदाहरण के लिए दोनों में एक IConnection हो सकता है, लेकिन इंटरफ़ेस अलग है - एक सामान्य नामस्थान से नहीं)।

तो मेरी बात पर, मैं एक इंटरफ़ेस बना सकता है:

public interface IMessageReceiver{
  void AddSubscription(ISubscription subscriptionDetails)
}

दो प्रौद्योगिकियों के गैर-अनुवाद योग्य गुणों के कारण, उपरोक्त इंटरफ़ेस के सर्विसबस और रैबिटएमक्यू कार्यान्वयनों की अलग-अलग आवश्यकताएं हैं। तो मेरा RabbitMq IMessageReceiver का इम्प्लांटेशन इस तरह दिख सकता है:

public void AddSubscription(ISubscription subscriptionDetails){
  if(!subscriptionDetails is RabbitMqSubscriptionDetails){
    // I have a problem!
  }
}

मेरे लिए, ऊपर की लाइन प्रतिस्थापन की Liskov के नियम को तोड़ती है।

मैंने इसे इधर-उधर फ़्लिप करने पर विचार किया, ताकि एक सदस्यता एक IMessageConnection को स्वीकार कर ले, लेकिन फिर से RabbitMq सदस्यता को RabbitMQMessageConnection के विशिष्ट गुणों की आवश्यकता होगी।

तो, मेरे सवाल हैं:

  • क्या मैं सही हूं कि इससे एलएसपी टूट जाता है?
  • क्या हम इस बात से सहमत हैं कि कुछ मामलों में यह अपरिहार्य है, या, क्या मुझे कुछ याद आ रहा है?

उम्मीद है, यह स्पष्ट और विषय पर है!


क्या इंटरफ़ेस के लिए एक प्रकार का पैरामीटर जोड़ना आपके लिए एक विकल्प है? जावा-सिंटैक्स के संदर्भ में, कुछ interface TestInterface<T extends ISubscription>ऐसा स्पष्ट रूप से संवाद करेगा कि कौन से प्रकार स्वीकार किए जाते हैं, और यह कि कार्यान्वयन के बीच अंतर हैं।
हल्क

@ हल्क, मुझे ऐसा विश्वास नहीं है, क्योंकि प्रत्येक कार्यान्वयन के लिए आईएसबीसक्रिप्शन के एक अलग कार्यान्वयन की आवश्यकता होगी।
गिंजानांजा

1
क्षमा करें, जो मैं प्रस्तावित करना चाहता था interface IMessageReceiver<T extends ISubscription>{void AddSubscription(T subscriptionDetails); }। एक कार्यान्वयन तब public class RabbitMqMessageReceiver implements IMessageReceiver<RabbitMqSubscriptionDetails> { public void AddSubscription(RabbitMqSubscriptionDetails subscriptionDetails){} }(जावा में) जैसा दिख सकता है ।
हल्क

जवाबों:


11

हां, यह एलएसपी को तोड़ता है, क्योंकि आप स्वीकार किए गए मूल्यों की संख्या को सीमित करके उप-वर्ग के दायरे को कम कर रहे हैं, आप पूर्व-शर्तों को पूरा कर रहे हैं। अभिभावक इसे स्वीकार करते हैं ISubscriptionलेकिन बच्चा ऐसा नहीं करता।

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

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


धन्यवाद। मैं यह नहीं सोच सकता कि बिना मुद्दे को आगे बढ़ाए इसे कैसे 'फ्लिप' किया जाए। उदाहरण के लिए सदस्यता को संदेश प्राप्त करने के लिए RabbitMQ के लिए IModel और ServiceBus के लिए कुछ और जानना होगा। मुझे लगता है कि एनोटेट अपवाद ही आगे बढ़ने का एकमात्र तरीका है।
गिंजानिजा

2

हां, यहां आपका कोड LSP टूट जाता है। ऐसे मामलों में, मैं डीडीडी डिज़ाइन पैटर्न से भ्रष्टाचार निरोधक परत का उपयोग करूंगा। आप वहां एक उदाहरण देख सकते हैं: http://www.markhneedham.com/blog/2009/07/07/domain-driven-design-ant-corruption-layer/

विचार यह है कि उप-प्रणाली पर निर्भरता को जितना संभव हो उतना कम करके इसे अलग-थलग कर दिया जाए, इसके लिए आवश्यकता पड़ने पर रिफैक्टिंग को कम से कम किया जाए।

आशा करता हूँ की ये काम करेगा !

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.