اخبار، مطالب و رویدادهای مرتبط با توسعه نرم افزار رادکام

الگوی طراحی Observer

الگوی Observer یکی از الگوهای رفتاری می باشد. همان طور که از نام این الگو مشخص است، در این الگو برخی اشیا عملکرد شی خاصی را مشاهده یا رصد می کنند و هر گونه تغییر در وضعیت شی مورد نظر بر روی اشیا ناظر تاثیر گذار خواهد بود. به این ترتیب وابستگی بین اشیا ناظر و شی هدف وجود دارد و نیاز است که همه اشیا ناظر از هر گونه تغییر حالت شی هدف اطلاع پیدا کنند. یکی از راه حل هایی که برای این سناریو وجود دارد استفاده از حلقه For می باشد. اما این راه حل هزینه بر بوده و کارایی را کاهش می دهد. لذا در چنین مواردی استفاده از الگوی Observer بسیار کمک کننده خواهد بود. این الگوی طراحی بسیار کاربردی می باشد و از ارتباط Broadcast پشتیبانی می کند. Observer یکی از مهمترین بخش های معماری MVC محسوب می شود.

کاربردهای الگوی طراحی Observer

الگوی Observer را می توان در موارد زیر استفاده نمود:

  • در مواردی که بخواهیم عملیات و توابع مختلفی را که در یک abstract قرار دارند در اشیاء متفاوتی پیاده سازی نمود به طوری که این اشیاء مستقل از یکدیگر باشند و نیاز به اطلاع رسانی از تغییرات به این اشیاء وجود داشته باشد.
  • در مواردی که پس از ایجاد تغییر در یک شیء قرار باشد که سایر اشیاء که تعداد آن ها مشخص نیست عملیات خاصی را انجام دهند.
  • در مواردی پس از ایجاد تغییر در یک شیء قرار باشد که به سایر اشیاء بدون توجه به نوع و نحوه پیاده سازی آن ها اطلاع رسانی شود.

روش های ارتباط Subject و Observer

برای ارتباط بین Subject و Observer دو روش وجود دارد:

  • روش Push: در این روش Subject همه تغییرات انجام شده را برای کلیه Observerها به صورت کامل ارسال می کند و هر کدام از اشیا آدر صورتی که نیاز به آپدیت یا تغییری داشته باشند اطلاعات مورد نیاز خود را استخراج می نمایند.
  • روش Pull: در این روش Subject به همه Observerها اطلاع می دهد که تغییری انجام شده است و هر کدام از Observerها که نیاز به آپدیت یا تغییر داشته باشند پیامی برای ارسال کامل اطلاعات را به Subject می فرستند و پس از آن Subject به اشیایی که درخواست اطلاعات نموده اند تغییرات درخواست شده را ارسال می نماید.

نمودار کلاس دیاگرام الگوی طراحی Observer

Observer Pattern Diagram

همان طور که در دیاگرام مشخص است نمودار کلاس الگوی Observer شامل کلاس های زیر است:

  • کلاس Subject: کلاس هدف می باشد که تغییرات آن برای سایر اشیا اهمیت دارد و در واقع ممکن است یک یا چند کلاس به عنوان مشاهده کننده تغییرات آن را دنبال کنند. در این کلاس توابعی برای افزودن یا حذف مشاهده کننده ها پیاده سازی می شود.
  • کلاس ConcreteSubject: وضعیت مشاهده کننده ها در این کلاس نگهداری می شود و در زمان هایی که تغییراتی  در هدف رخ می دهد، پیام های لازم را به مشاهده کننده ها ارسال می کند.
  • کلاس Observer: کلاس مشاهده کننده که تغییرات Subject برای آن مهم است و متد Update برای اطلاع رسانی به اشیا را پیاده سازی می نماید.
  • کلاس ConcreteObserver: یک مرجع برای اشیا ConcreteSubject ایجاد می کند و حالتی که توسط Subject باید پایدار بماند را ذخیره می کند. همچنین برای آپدیت Subjectها متدی را پیاده سازی می کند.

در ادامه، پیاده سازی این الگو را در یک مثال توضیح می دهیم:

همان طور که می دانیم، در بورس شرکت ها و سهامداران مختلفی وجود دارند و هر کدام از سهامداران ممکن است سهام یک یا چندین شرکت را داشته باشند. بنابراین تغییر در قیمت هر  کدام از شرکت ها برای شهامداران آن شرکت مهم بوده و نیاز دارند که از تغییرات شرکت خود اطلاع داشته باشند. در صورتی که بخواهیم اطلاع رسانی برای هر سهامدار در هر شرکت را با استفاده از عملگرهای کنترلی حلقه ها پیاده سازی نماییم ممکن است کاری پر هزینه باشد اما این سناریو به راحتی می تواند با استفاده از الگوی طراحی Observer پیاده سازی شود.

کلاس Stock که در واقع کلاس هدف می باشد و پیاده سازی آن به صورت زیر انجام می شود:


    abstract class Stock
    {
        private string _symbol;
        private double _price;
        private List _investors = new List();

        public Stock(string symbol, double price)
        {
            this._symbol = symbol;
            this._price = price;
        }

        public void Attach(IInvestor investor)
        {
            _investors.Add(investor);
        }

        public void Detach(IInvestor investor)
        {
            _investors.Remove(investor);
        }

        public void Notify()
        {
            foreach (IInvestor investor in _investors)
            {
                investor.Update(this);
            }

            Console.WriteLine("");
        }

        public double Price
        {
            get { return _price; }
            set

            {
                if (_price != value)
                {
                    _price = value;
                    Notify();
                }
            }
        }

        public string Symbol
        {
            get { return _symbol; }
        }
    }
}

برای هر کدام از شرکت ها مثلا IBM که نقش ConcreteSubject را داشته می توان کلاسی به صورت زیر پیاده سازی نمود که از کلاس Subject ارث بری می کند:


    class IBM : Stock

    {
        public IBM(string symbol, double price)
          : base(symbol, price)
        {
        }
    }

Interfaceی برای سهامداران که در واقع به عنوان مشاهده کننده در نظر گرفته می شود تا تغییرات را پیاده سازی نماید و به صورت زیر می باشد:


    interface IInvestor

    {
        void Update(Stock stock);
    }


کلاس سهامداران که نقش ConcreteObserver را داشته و از کلاس IInvestor ارث بری نموده است. این کلاس به صورت زیر پیاده سازی می شود:


class Investor : IInvestor

    {
        private string _name;
        private Stock _stock;

        // Constructor
        public Investor(string name)
        {
            this._name = name;
        }

        public void Update(Stock stock)
        {
            Console.WriteLine("Notified {0} of {1}'s " +
              "change to {2:C}", _name, stock.Symbol, stock.Price);
        }

        // Gets or sets the stock
        public Stock Stock
        {
            get { return _stock; }
            set { _stock = value; }
        }
    }

بنابراین در برنامه می توان پس از تعریف شرکت های مختلف و اختصاص سهامداران مختلف به آن ها، با هر بار تغییر قیمت، بدون درگیر شدن برای پیاده سازی اطلاع رسانی، به سهامداران اطلاع رسانی نمود:


IBM ibm = new IBM("IBM", 120.00);
ibm.Attach(new Investor("Sorros"));
ibm.Attach(new Investor("Berkshire"));

ibm.Price = 120.10;
ibm.Price = 121.00;
ibm.Price = 120.50;
ibm.Price = 120.75;
پست های مرتبط

نام را وارد کنید
تعداد کاراکتر باقیمانده: 1000
نظر خود را وارد کنید