এই নিবন্ধে, আপনি কিছু বর্ধন সহ .NET C#-এ অবজারভার ডিজাইন প্যাটার্ন সম্পর্কে শিখবেন।
অবজারভার ডিজাইন প্যাটার্ন হল সবচেয়ে গুরুত্বপূর্ণ এবং সাধারণভাবে ব্যবহৃত ডিজাইন প্যাটার্নগুলির মধ্যে একটি।
প্রথমে, অবজারভার ডিজাইন প্যাটার্নের আনুষ্ঠানিক সংজ্ঞা পরীক্ষা করা যাক।
যেমনটি
পর্যবেক্ষক ডিজাইন প্যাটার্ন একজন গ্রাহককে একটি প্রদানকারীর সাথে নিবন্ধন করতে এবং বিজ্ঞপ্তি পেতে সক্ষম করে। এটি যে কোনও পরিস্থিতির জন্য উপযুক্ত যার জন্য পুশ-ভিত্তিক বিজ্ঞপ্তি প্রয়োজন৷ প্যাটার্নটি একটি প্রদানকারীকে (একটি বিষয় বা একটি পর্যবেক্ষণযোগ্য হিসাবেও পরিচিত) এবং শূন্য, এক বা একাধিক পর্যবেক্ষককে সংজ্ঞায়িত করে। পর্যবেক্ষকরা প্রদানকারীর সাথে নিবন্ধন করে, এবং যখনই একটি পূর্বনির্ধারিত অবস্থা, ঘটনা, বা অবস্থার পরিবর্তন ঘটে, প্রদানকারী স্বয়ংক্রিয়ভাবে সমস্ত পর্যবেক্ষককে তাদের একটি পদ্ধতিতে কল করে অবহিত করে। এই পদ্ধতি কলে, প্রদানকারী পর্যবেক্ষকদের বর্তমান অবস্থার তথ্য প্রদান করতে পারে। .NET-এ, সাধারণ System.IObservable<T> এবং System.IObserver<T> ইন্টারফেস প্রয়োগ করে পর্যবেক্ষক নকশা প্যাটার্ন প্রয়োগ করা হয়। জেনেরিক টাইপ প্যারামিটার সেই ধরনের প্রতিনিধিত্ব করে যা বিজ্ঞপ্তি তথ্য প্রদান করে।
আমরা এখন জানি, অবজারভার ডিজাইন প্যাটার্ন পর্যবেক্ষণযোগ্য এবং পর্যবেক্ষক মডিউলের মধ্যে সম্পর্ক তৈরি করে। যা পর্যবেক্ষক ডিজাইন প্যাটার্নটিকে অনন্য করে তোলে তা হল এটি ব্যবহার করে আপনি শক্তভাবে সংযুক্ত সম্পর্ক ছাড়াই এটি অর্জন করতে পারেন।
প্যাটার্নটি কীভাবে কাজ করে তা বিশ্লেষণ করে আপনি নিম্নলিখিতগুলি পাবেন:
এগুলি হল .NET C# এ অবজারভার ডিজাইন প্যাটার্ন বাস্তবায়নের জন্য ব্যবহৃত বিমূর্ততা ।
এটি একটি Covariant ইন্টারফেস যে কোনো পর্যবেক্ষণযোগ্য প্রতিনিধিত্ব করে। আপনি যদি .NET-এ ভেরিয়েন্স সম্পর্কে আরও জানতে চান, আপনি নিবন্ধটি দেখতে পারেন
এই ইন্টারফেসে সংজ্ঞায়িত সদস্য হল:
public IDisposable Subscribe (IObserver<out T> observer);
Subscribe
পদ্ধতিটি পর্যবেক্ষণযোগ্যকে জানাতে বলা উচিত যে কিছু পর্যবেক্ষক তার তথ্যের প্রবাহে আগ্রহী।
Subscribe
পদ্ধতি একটি বস্তু প্রদান করে যা IDisposable
ইন্টারফেস প্রয়োগ করে। এই বস্তুটি পর্যবেক্ষক দ্বারা প্রদত্ত তথ্যের প্রবাহ থেকে সদস্যতা ত্যাগ করতে ব্যবহার করা যেতে পারে। একবার এটি হয়ে গেলে, পর্যবেক্ষককে তথ্যের প্রবাহের কোনো আপডেট সম্পর্কে অবহিত করা হবে না।
এটি একটি বিরোধী ইন্টারফেস যা কোনো পর্যবেক্ষকের প্রতিনিধিত্ব করে। আপনি যদি .NET-এ ভেরিয়েন্স সম্পর্কে আরও জানতে চান, আপনি নিবন্ধটি দেখতে পারেন
এই ইন্টারফেসে সংজ্ঞায়িত সদস্য হল:
public void OnCompleted (); public void OnError (Exception error); public void OnNext (T value);
OnCompleted
পদ্ধতিটি পর্যবেক্ষণযোগ্য দ্বারা কল করা উচিত যাতে পর্যবেক্ষককে জানানো হয় যে তথ্যের প্রবাহ সম্পূর্ণ হয়েছে এবং পর্যবেক্ষকের আর কোনও তথ্য আশা করা উচিত নয়।
OnError
পদ্ধতিটি পর্যবেক্ষণযোগ্য দ্বারা কল করা উচিত যাতে পর্যবেক্ষককে জানানো হয় যে একটি ত্রুটি ঘটেছে।
OnNext
পদ্ধতিটি পর্যবেক্ষণযোগ্য দ্বারা পর্যবেক্ষককে জানাতে হবে যে তথ্যের একটি নতুন অংশ প্রস্তুত এবং স্ট্রীমে যুক্ত করা হচ্ছে।
এখন, দেখা যাক কিভাবে মাইক্রোসফট C# এ অবজারভার ডিজাইন প্যাটার্ন বাস্তবায়নের সুপারিশ করে। পরে, আমি আপনাকে কিছু ছোটখাটো উন্নতি দেখাব যা আমি নিজে প্রয়োগ করেছি।
আমরা একটি সাধারণ আবহাওয়ার পূর্বাভাস কনসোল অ্যাপ্লিকেশন তৈরি করব। এই অ্যাপ্লিকেশনটিতে, আমাদের কাছে WeatherForecast মডিউল (অবজারভেবল, প্রোভাইডার, বিষয়) এবং WeatherForecastObserver মডিউল (পর্যবেক্ষক) থাকবে।
সুতরাং, এর বাস্তবায়ন অনুসন্ধান শুরু করা যাক.
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
নিবন্ধন করতে পারে। বাস্তব জগতে, এটি একটি অভ্যন্তরীণ নির্ধারিত API কল বা সিগন্যালআর হাবের শ্রোতা বা অন্য কিছু যা তথ্যের উত্স হিসাবে কাজ করবে দ্বারা প্রতিস্থাপিত হতে পারে।
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
পদ্ধতিতে, আমরা কনসোলে "Error" লিখছি।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(); } } }
আমরা এখানে যা লক্ষ্য করতে পারি:
যখন আমি মাইক্রোসফ্টের বাস্তবায়ন পরীক্ষা করেছি, তখন আমি কিছু উদ্বেগ খুঁজে পেয়েছি। তাই, আমি কিছু ছোটখাট পরিবর্তন করার সিদ্ধান্ত নিয়েছি।
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>
ইন্টারফেসের উপরে নির্মিত লাইব্রেরিগুলি আরও দুর্দান্ত বৈশিষ্ট্য এবং ক্ষমতা প্রদান করে যা আপনার কাছে দরকারী বলে মনে হতে পারে।
এই লাইব্রেরি হল
অতএব, আমি আপনাকে এই লাইব্রেরিগুলি অন্বেষণ করতে এবং সেগুলি চেষ্টা করার জন্য উত্সাহিত করি৷ আমি নিশ্চিত যে আপনি তাদের কিছু পছন্দ করবেন।
এছাড়াও এখানে প্রকাশিত.