این سایت برای ie9 طراحی نشده است

لطفا دستگاه خود را بچرخانید.

آموزش الگوی طراحی برنامه نویسی Observer Design Pattern

۱۶ خرداد ۱۳۹۶ حسین صداقت
بدون دیدگاه

به نام خدا

همانطور که در مطلب قبل اشاره کردیم در این این مطلب می خواهیم الگوی طراحی Observer رو با هم بررسی کنیم.این الگو زمانی مور استفاده قرار میگیرد که ما چندین شی داریم (Observers) که به یک شی (Subject)  وابسته هستند و زمانی که Subject ما تغییر حالت می دهد نیاز است شی های Observer ما ازین تغییر حالت آگاه شوند.نمودار UML این الگو به صورت زیر است :

 

Observer pattern

نقش های شرکت کننده در این الگو موارد زیر هستند:

–Subject : Observers هایش را می شناسند.تعدادی Observer می توانند به یک Subject وابسته باشند.همچنین یک Interface جهت اضافه یا کم کردن Observer در اختیار قرار می دهد.

–ConcreteSubject : حالت های مختلف یک Subject را در خود دارد.زمانی که تغییر حالت می دهد به Observer هایش اعلام می کند.

–Observer : یک Updating Interfaceجهت دریافت Notification تغییرات Subject در اختیار قرار می دهد.

–ConcreteObserver : یک Refrence به شی ConcreteSubject در خود دارد.حالتی را که باید توسط Subject ها پایدار بماند را در خود دارد.پیاده سازی می کند  Updating Interface  جهت دریافت حالت به روز شده Subject ها.

سناریوی زیر را در نظر بگیرید :

فرض کنید شرکت بورس می خواهد برنامه ای بنویسد که ا تغییر قیمت سهام یک شرکت ، آن را به دارندگان و سرمایه گذاران آن سهام اعلام کند.برای این امر ابتدا ما کلاس انتزاعی Stock که نقش Subject را برای ما دارد پیاده سازی می کنیم:

abstract class Stock
{
  private string _symbol;
  private double _price;
  private List<IInvestor> _investors = new List<IInvestor>();
 
  // Constructor
  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("");
  }
 
  // Gets or sets the price
  public double Price
  {
    get { return _price; }
    set
    {
      if (_price != value)
      {
        _price = value;
        Notify();
      }
    }
  }
 
  // Gets the symbol
  public string Symbol
  {
    get { return _symbol; }
  }
}

 

این کلاس دارای ۳ فیلد به نام های _symbol (نماد شرکت در بورس) و _price ( قیمت) و _investors (سهامداران) می باشد که مقادیر _price و  _symbol در Constructor کلاس ست می شود.فیلد _investors که لیستی از نوع Iinvestor (سهامداران) توسط متد Attach این کلاس به آن اضافه می شود و توسط متد Detach از آن حذف می شود.همچنین متد Notify وظیفه call کردن متد Update  Investor ها را با ارسال وضعیت فعلی کلاس بر عهده دارد.این کلاس دارای دو Property نیز می باشد که در Property Price فیلد _price امکان Get و Set شدن دارند.فقط نکته ای که وجود دارند این است که در هنگام Set شدن Price Property اگر مقداری که در حال ست شدن است با مقدار فعلی متفاوت باشد متد Notify که وظیفه آن ارسال Notification به سهامداران بود صدا زده می شود.Property Symbol نیز فقط امکان گرفتن (Get کردن) دارد و امکان ست کردن مقدار را ندارد.

کلاس بعدی که به آن می پردازیم کلاسی است که ما به ازای هر شرکتی در بورس دارای سهام است باید آن را پیاده سازی کنیم و همان نقش Concrete Subject را برای ما دارد.

class IBM : Stock
 {
   // Constructor
   public IBM(string symbol, double price)
     : base(symbol, price)
   {
   }
 }

به طور مثال ما می خواهیم کلاس مربوط به شرکت IBM را پیاده سازی کنیم .پس یک کلاس به اسم IBM می سازیم که از کلاس Stock ارث می برد و در Constuctor آن ، Constructor کلاس Stock صدا زده می شود و مقادیر _price و _symbol به آن پاس داده می شود.

نقش بعدی که پیاده سازی می کنیم یک Interface به اسم IInvestor می باشد که نقش Observer را برای ما دارد و ساختار متد Update در آن تعریف شده است که ورودی این متد یک شی از جنس Stock می باشد و خروجی ندارد.

interface IInvestor
{
  void Update(Stock stock);
}

 

و در آخر کلاس Investor که نقش 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; }
    }
  }
}

 

این کلاس دارای دو فیلد با نام های _name و _stock  می باشد که فیلد _stock از نوع کلاس Stock  است.

فیلد _name در Constructor این کلاس مقدار دهی می شود .فیلد _stock نیز توسط Property Stock این کلاس امکان Set و Get شدن مقدار دارد. متد Update نیز که ورودی آن یک شی از نوع stock می باشد وظیفه چاپ مقادیر شی ورودی بر روی Console را بر عهده دارد.

و در انتها نحوه استفاده از کلاس ها به صورت زیر می شود:

class MainApp
{
  /// <summary>
  /// Entry point into console application.
  /// </summary>
  static void Main()
  {
    // Create IBM stock and attach investors
    IBM ibm = new IBM("IBM", 120.00);
    ibm.Attach(new Investor("Sorros"));
    ibm.Attach(new Investor("Berkshire"));
 
    // Fluctuating prices will notify investors
    ibm.Price = 120.10;
    ibm.Price = 121.00;
    ibm.Price = 120.50;
    ibm.Price = 120.75;
 
    // Wait for user
    Console.ReadKey();
  }
}

 

که در اینجا با هر تغییر قیمت Investor های سهام شرکت IBM از تغییرات مطلع می شوند وقیمت جدید بر روی Console به نمایش در می آید.

در مطلب بعدی الگوی طراحی State را بررسی می کنیم.موفق باشید

منبع : http://www.dofactory.com/