ढीले युग्मित कोड के लिए इंटरफेस का उपयोग करना


10

पृष्ठभूमि

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

  1. एक C # प्रोजेक्ट में एक इंटरफ़ेस परिभाषित करें IDevice
  2. किसी अन्य C # प्रोजेक्ट में परिभाषित लाइब्रेरी में एक कंक्रीट रखें, जिसका उपयोग डिवाइस का प्रतिनिधित्व करने के लिए किया जाएगा।
  3. IDeviceइंटरफ़ेस को लागू करने के लिए ठोस उपकरण रखें ।
  4. IDeviceइंटरफ़ेस की तरह तरीकों हो सकता है GetMeasurementया SetRange
  5. एप्लिकेशन को कंक्रीट के बारे में ज्ञान है, और कंक्रीट को एप्लिकेशन कोड में पास करें जो उपकरण का उपयोग करता है ( लागू नहीं ) IDevice

मुझे पूरा यकीन है कि इसके बारे में जाने का यह सही तरीका है, क्योंकि तब मैं यह पता लगाने में सक्षम हो जाऊंगा कि एप्लिकेशन को प्रभावित किए बिना किस डिवाइस का उपयोग किया जा रहा है (जो कभी-कभी लगता है)। दूसरे शब्दों में, इससे कोई फर्क नहीं पड़ेगा कि कंक्रीट के माध्यम से GetMeasurementया SetRangeवास्तव में कार्यान्वयन कैसे होता है (जैसा कि डिवाइस के निर्माताओं के बीच भिन्न हो सकता है)।

मेरे दिमाग में एकमात्र संदेह यह है कि अब दोनों आवेदन, और डिवाइस का ठोस वर्ग दोनों उस लाइब्रेरी पर निर्भर करता है जिसमें IDeviceइंटरफ़ेस शामिल है। लेकिन, क्या यह बुरी बात है?

मैं यह भी नहीं देखता कि डिवाइस के बारे में एप्लिकेशन को जानने की आवश्यकता नहीं होगी, जब तक कि डिवाइस और IDeviceएक ही नामस्थान में न हों।

सवाल

क्या यह मेरे आवेदन और उस डिवाइस के बीच निर्भरता को कम करने के लिए एक इंटरफ़ेस को लागू करने के लिए सही दृष्टिकोण की तरह लगता है जो इसका उपयोग करता है?


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

@KilianFoth हाँ मुझे एक एहसास था, अपने सवाल में एक हिस्सा जोड़ना भूल गया। # 5 देखें।
स्नूप

जवाबों:


5

मुझे लगता है कि आप समझ गए होंगे कि सॉफ्टवेयर कैसे काम करता है :)

मेरे दिमाग में एकमात्र संदेह यह है कि अब दोनों आवेदन, और डिवाइस का ठोस वर्ग दोनों उस लाइब्रेरी पर निर्भर करता है जिसमें IDevice इंटरफ़ेस है। लेकिन, क्या यह बुरी बात है?

यह होने की जरूरत नहीं है!

मैं यह भी नहीं देखता कि एप्लिकेशन को डिवाइस के बारे में जानने की आवश्यकता नहीं होगी, जब तक कि डिवाइस और IDevice एक ही नाम स्थान पर न हों।

आप प्रोजेक्ट संरचना के साथ इन सभी चिंताओं से निपट सकते हैं ।

जिस तरह से मैं आम तौर पर यह करते हैं:

  • एक Commonपरियोजना में मेरे सभी सार सामान रखो । कुछ इस तरह MyBiz.Project.Common। अन्य परियोजनाएं इसे संदर्भित करने के लिए स्वतंत्र हैं, लेकिन यह अन्य परियोजनाओं को संदर्भित नहीं कर सकता है।
  • जब मैं एक अमूर्त के ठोस कार्यान्वयन का निर्माण करता हूं तो मैं इसे एक अलग परियोजना में डाल देता हूं। कुछ इस तरह MyBiz.Project.Devices.TemperatureSensors। यह प्रोजेक्ट प्रोजेक्ट को संदर्भित करेगा Common
  • मेरे पास तब मेरा Clientप्रोजेक्ट है जो मेरे आवेदन के लिए प्रविष्टि है (कुछ इस तरह MyBiz.Project.Desktop)। स्टार्टअप पर, एप्लिकेशन बूटस्ट्रैपिंग प्रक्रिया से गुजरता है जहां मैं अमूर्त / कंक्रीट-कार्यान्वयन मैपिंग को कॉन्फ़िगर करता हूं। मैं अपनी कंक्रीट IDevicesको यहां WaterTemperatureSensorऔर IRCameraTemperatureSensorयहां या तो तुरंत चालू कर सकता हूं , या मैं बाद में मेरे लिए सही ठोस प्रकारों को तुरंत बदलने के लिए फैक्ट्रियों या आईओसी कंटेनर जैसी सेवाओं को कॉन्फ़िगर कर सकता हूं।

यहां महत्वपूर्ण बात यह है कि केवल आपकी Clientपरियोजना को अमूर्त Commonपरियोजना और सभी ठोस कार्यान्वयन परियोजनाओं के बारे में पता होना चाहिए । अपने बूटस्ट्रैप कोड में अमूर्त-> ठोस मानचित्रण को सीमित करके आप अपने बाकी के आवेदन के लिए यह संभव कर रहे हैं कि आप ठोस प्रकारों से अनजान रहें।

ढीली युग्मित कोड ftw :)


2
DI यहाँ से स्वाभाविक रूप से अनुसरण करता है। यह काफी हद तक एक परियोजना / कोड संरचना चिंता का विषय है। IoC कंटेनर होने से DI को मदद मिल सकती है, लेकिन यह एक शर्त नहीं है। आप मैन्युअल रूप से निर्भरता को भी इंजेक्ट करके DI प्राप्त कर सकते हैं!
मेटाफ़ाइट

1
@StevieV हाँ, यदि आपके आवेदन के भीतर Foo ऑब्जेक्ट के लिए IDevice की आवश्यकता है, तो डिपेंडेंसी इनवर्जन एक निर्माणकर्ता ( new Foo(new DeviceA());) के माध्यम से इसे इंजेक्ट करना जितना आसान हो सकता है , बल्कि खुद Foo Instantiate DeviceA के भीतर एक निजी क्षेत्र होने के बजाय ( private IDevice idevice = new DeviceA();) - आप अभी भी DI को प्राप्त करते हैं। फू पहले मामले में DeviceA से अनजान है
दूसरा

2
@anotherdave तुम्हारा और मेटाफ़ाइट इनपुट बहुत मददगार था।
स्नूप

1
@StevieV जब आपको समय मिलता है, तो यहाँ एक अवधारणा के रूप में डिपेंडेंसी इनवर्जन का एक अच्छा परिचय है ("अंकल बॉब" मार्टिन से, इसे तैयार करने वाले व्यक्ति), स्प्रिंग / (या कुछ और जैसे कंट्रोल / डिपेंडेन्सी इंजेक्शन फ्रेमवर्क के इनवर्टर से अलग है)
C example

1
@anotherdave निश्चित रूप से उस जाँच की योजना बना रहा है, फिर से धन्यवाद।
स्नूप

3

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

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

संपादित करें

अपनी पांचवीं चिंता को संबोधित करते हुए, इस तरह की संरचना के बारे में सोचें (मैं मान रहा हूं कि आप अपने उपकरणों को परिभाषित करने के नियंत्रण में हैं):

आपके पास एक मुख्य पुस्तकालय है। इसमें एक इंटरफ़ेस है जिसे IDevice कहा जाता है।

आपके डिवाइस लाइब्रेरी में, आपके पास अपनी मुख्य लाइब्रेरी का संदर्भ होता है, और आपने उन उपकरणों की एक श्रृंखला को परिभाषित किया है, जो सभी IDevice को लागू करते हैं। आपके पास एक कारखाना भी है जो जानता है कि विभिन्न प्रकार के IDevices कैसे बनाएं।

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

यह आपकी चिंताओं को दूर करने के कई संभावित तरीकों में से एक है।

उदाहरण:

namespace Core
{
    public interface IDevice { }
}


namespace Devices
{
    using Core;

    class DeviceOne : IDevice { }

    class DeviceTwo : IDevice { }

    public class Factory
    {
        public IDevice CreateDeviceOne()
        {
            return new DeviceOne();
        }

        public IDevice CreateDeviceTwo()
        {
            return new DeviceTwo();
        }
    }
}

// do not implement IDevice
namespace ThirdrdPartyDevices
{

    public class ThirdPartyDeviceOne  { }

    public class ThirdPartyDeviceTwo  { }

}

namespace DeviceAdapters
{
    using Core;
    using ThirdPartyDevices;

    class ThirdPartyDeviceAdapterOne : IDevice
    {
        private ThirdPartyDeviceOne _deviceOne;

        // use the third party device to adapt to the interface
    }

    class ThirdPartyDeviceAdapterTwo : IDevice
    {
        private ThirdPartyDeviceTwo _deviceTwo;

        // use the third party device to adapt to the interface
    }

    public class AdapterFactory
    {
        public IDevice CreateThirdPartyDeviceAdapterOne()
        {
            return new ThirdPartyDeviceAdapterOne();
        }

        public IDevice CreateThirdPartyDeviceAdapterTwo()
        {
            return new ThirdPartyDeviceAdapterTwo();
        }
    }
}

namespace Application
{
    using Core;
    using Devices;
    using DeviceAdapters;

    class App
    {
        void RunInHouse()
        {
            var factory = new Factory();
            var devices = new List<IDevice>() { factory.CreateDeviceOne(), factory.CreateDeviceTwo() };
            foreach (var device in devices)
            {
                // call IDevice  methods.
            }
        }

        void RunThirdParty()
        {
            var factory = new AdapterFactory();
            var devices = new List<IDevice>() { factory.CreateThirdPartyDeviceAdapterOne(), factory.CreateThirdPartyDeviceAdapterTwo() };
            foreach (var device in devices)
            {
                // call IDevice  methods.
            }
        }
    }
}

तो इस कार्यान्वयन के साथ, कंक्रीट कहाँ जाता है?
स्नूप

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

मुझे लगता है कि केवल एक चीज है, आवेदन को उस विशिष्ट कंक्रीट तक पहुंच कैसे मिलेगी जो मुझे चाहिए?
स्नूप

एक समाधान यह होगा कि आईडी बनाने के लिए अमूर्त कारखाना पैटर्न का उपयोग किया जाए।
मूल्य जोन्स

1

मेरे दिमाग में एकमात्र संदेह यह है कि अब दोनों आवेदन, और डिवाइस का ठोस वर्ग दोनों उस लाइब्रेरी पर निर्भर करता है जिसमें IDevice इंटरफ़ेस है। लेकिन, क्या यह बुरी बात है?

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

क्या यह मेरे आवेदन और उस डिवाइस के बीच निर्भरता को कम करने के लिए एक इंटरफ़ेस को लागू करने के लिए सही दृष्टिकोण की तरह लगता है जो इसका उपयोग करता है?

बस हाँ

कैसे ठोस वास्तव में एप्लिकेशन को मिलता है

एप्लिकेशन रनटाइम पर कंक्रीट असेंबली (dll) लोड कर सकता है। देखें: /programming/465488/can-i-load-a-net-assembly-at-runtime-and-instantiate-a-type-knowing-only-the-na

यदि आपको ऐसे "ड्राइवर" को गतिशील रूप से अनलोड / लोड करने की आवश्यकता है, तो आपको असेंबली को एक अलग AppDomain में लोड करने की आवश्यकता है ।


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

क्षमा करें, एक भाग को जोड़ना भूल गया (ऐप में कंक्रीट वास्तव में कैसे मिलता है)। क्या आप इसे संबोधित कर सकते हैं? # 5 देखें।
स्नूप

क्या आप वास्तव में अपने ऐप्स को इस तरह से करते हैं, रन-टाइम पर DLL लोड करते हैं?
स्नूप

उदाहरण के लिए यदि ठोस वर्ग मेरे द्वारा नहीं जाना जाता है तो हाँ। मान लें कि एक उपकरण विक्रेता आपके IDeviceइंटरफ़ेस का उपयोग करने का निर्णय लेता है, तो उसका उपकरण आपके ऐप के साथ उपयोग किया जा सकता है, तो कोई अन्य तरीका IMO नहीं होगा।
हेसलाचेर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.