इस लेख में, आप कुछ संवर्द्धन के साथ .NET C# में ऑब्जर्वर डिज़ाइन पैटर्न के बारे में जानेंगे।
ऑब्जर्वर डिज़ाइन पैटर्न सबसे महत्वपूर्ण और आमतौर पर इस्तेमाल किए जाने वाले डिज़ाइन पैटर्न में से एक है।
सबसे पहले, ऑब्जर्वर डिज़ाइन पैटर्न की औपचारिक परिभाषा की जाँच करें।
के अनुसार
प्रेक्षक डिजाइन पैटर्न एक ग्राहक को एक प्रदाता के साथ पंजीकरण करने और सूचनाएं प्राप्त करने में सक्षम बनाता है। यह किसी भी परिदृश्य के लिए उपयुक्त है जिसके लिए पुश-आधारित अधिसूचना की आवश्यकता होती है। पैटर्न एक प्रदाता (एक विषय या एक अवलोकन योग्य के रूप में भी जाना जाता है) और शून्य, एक या अधिक पर्यवेक्षकों को परिभाषित करता है। पर्यवेक्षक प्रदाता के साथ पंजीकरण करते हैं, और जब भी कोई पूर्वनिर्धारित स्थिति, घटना या राज्य परिवर्तन होता है, तो प्रदाता स्वचालित रूप से सभी पर्यवेक्षकों को उनके तरीकों में से एक को कॉल करके सूचित करता है। इस पद्धति कॉल में, प्रदाता पर्यवेक्षकों को वर्तमान स्थिति की जानकारी भी प्रदान कर सकता है। .NET में, सामान्य System.IObservable<T> और System.IObserver<T> इंटरफेस को लागू करके पर्यवेक्षक डिजाइन पैटर्न लागू किया जाता है। सामान्य प्रकार का पैरामीटर उस प्रकार का प्रतिनिधित्व करता है जो अधिसूचना जानकारी प्रदान करता है।
जैसा कि हम अब जानते हैं, ऑब्जर्वर डिज़ाइन पैटर्न ऑब्जर्वेबल और ऑब्जर्वर मॉड्यूल के बीच संबंध बनाता है। ऑब्जर्वर डिज़ाइन पैटर्न अद्वितीय बनाता है कि इसका उपयोग करके आप इसे कसकर युग्मित संबंध के बिना प्राप्त कर सकते हैं।
पैटर्न के काम करने के तरीके का विश्लेषण करने पर, आप निम्नलिखित पाएंगे:
ये .NET C# में ऑब्जर्वर डिज़ाइन पैटर्न को लागू करने के लिए उपयोग किए जाने वाले सार हैं।
यह एक Covariant इंटरफ़ेस है जो किसी भी ऑब्जर्वेबल का प्रतिनिधित्व करता है। यदि आप .NET में Variance के बारे में अधिक जानना चाहते हैं, तो आप इस लेख को देख सकते हैं
इस इंटरफ़ेस में परिभाषित सदस्य हैं:
public IDisposable Subscribe (IObserver<out T> observer);
Subscribe
विधि को ऑब्जर्वेबल को सूचित करने के लिए कहा जाना चाहिए कि कुछ ऑब्जर्वर इसकी जानकारी की धारा में रुचि रखते हैं।
Subscribe
विधि एक वस्तु लौटाती है जो IDisposable
इंटरफ़ेस को लागू करती है। ऑब्जर्वर द्वारा इस वस्तु का उपयोग ऑब्जर्वेबल द्वारा प्रदान की गई जानकारी की धारा से सदस्यता समाप्त करने के लिए किया जा सकता है। एक बार यह हो जाने के बाद, पर्यवेक्षक को सूचना की धारा में किसी भी अद्यतन के बारे में सूचित नहीं किया जाएगा।
यह किसी भी ऑब्जर्वर का प्रतिनिधित्व करने वाला एक कॉन्ट्रावैरिएंट इंटरफ़ेस है। यदि आप .NET में Variance के बारे में अधिक जानना चाहते हैं, तो आप इस लेख को देख सकते हैं
इस इंटरफ़ेस में परिभाषित सदस्य हैं:
public void OnCompleted (); public void OnError (Exception error); public void OnNext (T value);
ऑब्जर्वर को सूचित करने के लिए कि सूचना की धारा पूरी हो गई है और ऑब्जर्वर को और अधिक जानकारी की उम्मीद नहीं करनी चाहिए, OnCompleted
विधि को ऑब्जर्वेबल द्वारा बुलाया जाना चाहिए।
पर्यवेक्षक को यह सूचित करने के लिए कि एक त्रुटि हुई है, OnError
विधि को ऑब्जर्वेबल द्वारा बुलाया जाना चाहिए।
ऑब्जर्वर को सूचित करने के लिए ऑब्जर्वेबल द्वारा OnNext
विधि को कॉल किया जाना चाहिए कि जानकारी का एक नया टुकड़ा तैयार है और स्ट्रीम में जोड़ा जा रहा है।
अब, देखते हैं कि कैसे Microsoft C# में ऑब्जर्वर डिज़ाइन पैटर्न को लागू करने की अनुशंसा करता है। बाद में, मैं आपको कुछ छोटे एन्हांसमेंट दिखाऊंगा जिन्हें मैंने स्वयं लागू किया था।
हम एक साधारण मौसम पूर्वानुमान कंसोल एप्लिकेशन बनाएंगे। इस एप्लिकेशन में, हमारे पास वेदरफोरकास्ट मॉड्यूल (ऑब्जर्वेबल, प्रोवाइडर, सब्जेक्ट) और वेदरफोरकास्ट ऑब्जर्वर मॉड्यूल (ऑब्जर्वर) होगा।
तो, आइए कार्यान्वयन पर गौर करना शुरू करें।
namespace Observable { public class WeatherInfo { internal WeatherInfo(double temperature) { Temperature = temperature; } public double Temperature { get; } } }
यह सूचना धारा में प्रवाहित होने वाली सूचना के टुकड़े का प्रतिनिधित्व करने वाली इकाई है।
using System; using System.Collections.Generic; namespace Observable { public class WeatherForecast : IObservable<WeatherInfo> { private readonly List<IObserver<WeatherInfo>> m_Observers; private readonly List<WeatherInfo> m_WeatherInfoList; public WeatherForecast() { m_Observers = new List<IObserver<WeatherInfo>>(); m_WeatherInfoList = new List<WeatherInfo>(); } public IDisposable Subscribe(IObserver<WeatherInfo> observer) { if (!m_Observers.Contains(observer)) { m_Observers.Add(observer); foreach (var item in m_WeatherInfoList) { observer.OnNext(item); } } return new WeatherForecastUnsubscriber(m_Observers, observer); } public void RegisterWeatherInfo(WeatherInfo weatherInfo) { m_WeatherInfoList.Add(weatherInfo); foreach (var observer in m_Observers) { observer.OnNext(weatherInfo); } } public void ClearWeatherInfo() { m_WeatherInfoList.Clear(); } } }
हम यहाँ क्या देख सकते हैं:
WeatherForecast
क्लास IObservable<WeatherInfo>
लागू कर रहा है।Subscribe
विधि के कार्यान्वयन में, हम जांचते हैं कि पास ऑब्जर्वर पहले से पंजीकृत था या नहीं। यदि नहीं, तो हम इसे स्थानीय m_Observers
पर्यवेक्षकों की सूची में जोड़ते हैं। फिर, हम स्थानीय m_WeatherInfoList
सूची में सभी WeatherInfo
प्रविष्टियों पर एक-एक करके लूप करते हैं और ऑब्जर्वर के OnNext
मेथड को कॉल करके ऑब्जर्वर को इसके बारे में सूचित करते हैं।WeatherForecastUnsubscriber
वर्ग का एक नया उदाहरण लौटाते हैं।RegisterWeatherInfo
विधि को परिभाषित किया गया है ताकि मुख्य मॉड्यूल नए WeatherInfo
पंजीकृत कर सके। वास्तविक दुनिया में, इसे एक आंतरिक अनुसूचित एपीआई कॉल या एक सिग्नलआर हब के श्रोता या कुछ और द्वारा प्रतिस्थापित किया जा सकता है जो सूचना के स्रोत के रूप में कार्य करेगा।
using System; using System.Collections.Generic; namespace Observable { public class Unsubscriber<T> : IDisposable { private readonly List<IObserver<T>> m_Observers; private readonly IObserver<T> m_Observer; private bool m_IsDisposed; public Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer) { m_Observers = observers; m_Observer = observer; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (m_IsDisposed) return; if (disposing && m_Observers.Contains(m_Observer)) { m_Observers.Remove(m_Observer); } m_IsDisposed = true; } ~Unsubscriber() { Dispose(false); } } }
हम यहाँ क्या देख सकते हैं:
IDisposable
लागू करता है।
using System; using System.Collections.Generic; namespace Observable { public class WeatherForecastUnsubscriber : Unsubscriber<WeatherInfo> { public WeatherForecastUnsubscriber( List<IObserver<WeatherInfo>> observers, IObserver<WeatherInfo> observer) : base(observers, observer) { } } }
हम यहाँ क्या देख सकते हैं:
Unsubscriber<T>
क्लास से इनहेरिट कर रहा है।
using System; namespace Observable { public class WeatherForecastObserver : IObserver<WeatherInfo> { private IDisposable m_Unsubscriber; public virtual void Subscribe(WeatherForecast provider) { m_Unsubscriber = provider.Subscribe(this); } public virtual void Unsubscribe() { m_Unsubscriber.Dispose(); } public void OnCompleted() { Console.WriteLine("Completed"); } public void OnError(Exception error) { Console.WriteLine("Error"); } public void OnNext(WeatherInfo value) { Console.WriteLine($"Temperature: {value.Temperature}"); } } }
हम यहाँ क्या देख सकते हैं:
WeatherForecastObserver
वर्ग IObserver<WeatherInfo>
लागू कर रहा है।OnNext
विधि पर, हम तापमान को कंसोल पर लिख रहे हैं।OnCompleted
मेथड पर, हम कंसोल पर "पूर्ण" लिख रहे हैं।OnError
विधि पर, हम कंसोल पर "त्रुटि" लिख रहे हैं।void Subscribe(WeatherForecast provider)
विधि को परिभाषित किया। अन-सब्सक्राइबर ऑब्जेक्ट लौटाया जाता है जो अनसब्सक्राइब करने की स्थिति में उपयोग करने के लिए आंतरिक रूप से सहेजा जाता है।void Unsubscribe()
विधि को परिभाषित किया गया है और यह आंतरिक रूप से सहेजे गए अन-सब्सक्राइबर ऑब्जेक्ट का उपयोग करता है।
using System; namespace Observable { class Program { static void Main(string[] args) { var provider = new WeatherForecast(); provider.RegisterWeatherInfo(new WeatherInfo(1)); provider.RegisterWeatherInfo(new WeatherInfo(2)); provider.RegisterWeatherInfo(new WeatherInfo(3)); var observer = new WeatherForecastObserver(); observer.Subscribe(provider); provider.RegisterWeatherInfo(new WeatherInfo(4)); provider.RegisterWeatherInfo(new WeatherInfo(5)); observer.Unsubscribe(); provider.RegisterWeatherInfo(new WeatherInfo(6)); observer.Subscribe(provider); provider.RegisterWeatherInfo(new WeatherInfo(7)); Console.ReadLine(); } } }
हम यहाँ क्या देख सकते हैं:
जब मैंने Microsoft के कार्यान्वयन की जाँच की, तो मुझे कुछ चिंताएँ मिलीं। इसलिए मैंने कुछ मामूली बदलाव करने का फैसला किया।
using System; using System.Collections.Generic; namespace ExtendedObservable { public interface IExtendedObservable<out T> : IObservable<T> { IReadOnlyCollection<T> Snapshot { get; } IDisposable Subscribe(IObserver<T> observer, bool withHistory); } }
हम यहाँ क्या देख सकते हैं:
IExtendedObservable<out T>
इंटरफ़ेस IObservable<T>
इंटरफ़ेस का विस्तार करता है।IReadOnlyCollection<T> Snapshot
प्रॉपर्टी को परिभाषित किया है ताकि अन्य मॉड्यूल को सब्सक्राइब किए बिना पहले से मौजूद जानकारी प्रविष्टियों की तत्काल सूची प्राप्त करने की अनुमति मिल सके।IDisposable Subscribe(IObserver<T> observer, bool withHistory)
मेथड को एक अतिरिक्त bool withHistory
पैरामीटर के साथ परिभाषित किया है ताकि ऑब्जर्वर यह तय कर सके कि वह पहले से मौजूद जानकारी प्रविष्टियों के बारे में सूचित करना चाहता है या नहीं।
using System; namespace ExtendedObservable { public class Unsubscriber : IDisposable { private readonly Action m_UnsubscribeAction; private bool m_IsDisposed; public Unsubscriber(Action unsubscribeAction) { m_UnsubscribeAction = unsubscribeAction; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (m_IsDisposed) return; if (disposing) { m_UnsubscribeAction(); } m_IsDisposed = true; } ~Unsubscriber() { Dispose(false); } } }
हम यहाँ क्या देख सकते हैं:
Unsubscriber
वर्ग सामान्य नहीं है।
using System; using System.Collections.Generic; namespace ExtendedObservable { public class WeatherForecastUnsubscriber : Unsubscriber { public WeatherForecastUnsubscriber( Action unsubscribeAction) : base(unsubscribeAction) { } } }
हम यहाँ क्या देख सकते हैं:
Unsubscriber<T>
से <T>
भाग को हटा दिया।Action
में लेता है।
using System; using System.Collections.Generic; namespace ExtendedObservable { public class WeatherForecast : IExtendedObservable<WeatherInfo> { private readonly List<IObserver<WeatherInfo>> m_Observers; private readonly List<WeatherInfo> m_WeatherInfoList; public WeatherForecast() { m_Observers = new List<IObserver<WeatherInfo>>(); m_WeatherInfoList = new List<WeatherInfo>(); } public IReadOnlyCollection<WeatherInfo> Snapshot => m_WeatherInfoList; public IDisposable Subscribe(IObserver<WeatherInfo> observer) { return Subscribe(observer, false); } public IDisposable Subscribe(IObserver<WeatherInfo> observer, bool withHistory) { if (!m_Observers.Contains(observer)) { m_Observers.Add(observer); if (withHistory) { foreach (var item in m_WeatherInfoList) { observer.OnNext(item); } } } return new WeatherForecastUnsubscriber( () => { if (m_Observers.Contains(observer)) { m_Observers.Remove(observer); } }); } public void RegisterWeatherInfo(WeatherInfo weatherInfo) { m_WeatherInfoList.Add(weatherInfo); foreach (var observer in m_Observers) { observer.OnNext(weatherInfo); } } public void ClearWeatherInfo() { m_WeatherInfoList.Clear(); } } }
हम यहाँ क्या देख सकते हैं:
IReadOnlyCollection<WeatherInfo> Snapshot
संपत्ति को छोड़कर लगभग समान है जो आंतरिक m_WeatherInfoList
सूची देता है लेकिन IReadOnlyCollection
के रूप में।IDisposable Subscribe(IObserver<WeatherInfo> observer, bool withHistory)
विधि जो withHistory
पैरामीटर का उपयोग करती है।
using System; namespace ExtendedObservable { public class WeatherForecastObserver : IObserver<WeatherInfo> { private IDisposable m_Unsubscriber; public virtual void Subscribe(WeatherForecast provider) { m_Unsubscriber = provider.Subscribe(this, true); } public virtual void Unsubscribe() { m_Unsubscriber.Dispose(); } public void OnCompleted() { Console.WriteLine("Completed"); } public void OnError(Exception error) { Console.WriteLine("Error"); } public void OnNext(WeatherInfo value) { Console.WriteLine($"Temperature: {value.Temperature}"); } } }
हम यहां जो नोटिस कर सकते हैं वह यह है कि Subscribe(WeatherForecast provider)
को छोड़कर यह लगभग समान है जो अब यह तय करता है कि इसे हिस्ट्री के साथ Subscribe
करना चाहिए या नहीं।
using System; namespace ExtendedObservable { class Program { static void Main(string[] args) { var provider = new WeatherForecast(); provider.RegisterWeatherInfo(new WeatherInfo(1)); provider.RegisterWeatherInfo(new WeatherInfo(2)); provider.RegisterWeatherInfo(new WeatherInfo(3)); var observer = new WeatherForecastObserver(); observer.Subscribe(provider); provider.RegisterWeatherInfo(new WeatherInfo(4)); provider.RegisterWeatherInfo(new WeatherInfo(5)); observer.Unsubscribe(); provider.RegisterWeatherInfo(new WeatherInfo(6)); observer.Subscribe(provider); provider.RegisterWeatherInfo(new WeatherInfo(7)); Console.ReadLine(); } } }
यह पहले जैसा ही है।
अब, आप .NET C# में ऑब्जर्वर डिज़ाइन पैटर्न की मूल बातें जानते हैं। हालाँकि, यह कहानी का अंत नहीं है।
IObservable<T>
और IObserver<T>
इंटरफेस के शीर्ष पर निर्मित पुस्तकालय हैं जो आपको अधिक उपयोगी सुविधाएं और क्षमताएं प्रदान करते हैं जो आपको उपयोगी लग सकते हैं।
इन पुस्तकालयों में से है
इसलिए, मैं आपको प्रोत्साहित करता हूं कि आप इन पुस्तकालयों का पता लगाएं और उन्हें आजमाएं। मुझे यकीन है कि आप उनमें से कुछ को पसंद करेंगे।