觀察者模式(Observer Pattern)

1、概述
在軟件設計工做中會存在對象之間的依賴關係,當某一對象發生變化時,全部依賴它的對象都須要獲得通知。若是設計的很差,很容易形成對象之間的耦合度過高,難以應對變化。使用觀察者模式能夠下降對象之間的依賴,以鬆耦合的方式實現這一目標。this


2、觀察者模式
觀察者模式定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並自動更新。其結構圖以下:spa

 

Subject知道它的全部觀察者並提供了觀察者註冊和刪除訂閱的接口。
Observer爲那些在目標發生改變時需得到通知的對象定義一個更新接口。
ConcreteSubject實現Subject接口,當改變狀態時向依賴於它的ConcreteObserver發送通知。
ConcreteObserver實現Observer的更新接口,使得自身能根據ConcreteSubject狀態的不一樣而作出相應的改變。
觀察者模式分爲推模式和拉模式兩種。推模式是當有通知時,把依賴對象的信息以參數的形式傳遞給全部觀察者,而拉模式通知方法自己並不帶任何的參數,是由觀察者本身到依賴對象那裏取回相關信息。在推模式下,全部觀察者都經過參數傳遞的方式獲得依賴對象的所有信息,與依賴對象之間的耦合較低,但不能實現「按需所取」所須要信息的。而拉模式僅僅是通知觀察者,至於要不要提取依賴對象的信息則是觀察者本身的事情,這麼一來就實現「按需所取」,但每每要在ConcreteObserver裏保存一個ConcreteSubject的引用,與ConcreteSubject的耦合也增強了。
觀察者模式的Subject通常須要提供觀察者註冊和刪除訂閱的接口,但在.NET中,每每能夠利用事件和委託的特性來實現觀察者模式,這是一種更爲優雅的方案。設計

 

3、示例
咱們如今利用事件實現觀察者模式。咱們設計一個信用卡消費的簡單例子,在消費的同時須要對用戶帳戶進行扣款,同時對用戶進行短信提醒。
首先定義信用卡類,當消費金額變更時會觸發Notify方法通知該對象的全部觀察者。code

public class CreditCard : EventArgs
    {
        private float _spendAmount;
        public event EventHandler<CreditCard> SpendMoney;

        public float SpendAmount
        {
            get
            {
                return _spendAmount;
            }
            set
            {
                _spendAmount = value;
                Notify();
            }
        }

        private void Notify()
        {
            if (SpendMoney != null)
            {
                SpendMoney(this, this);
            }
        }
    }

接着定義Observer接口,並使用戶賬戶類和短信提醒類實現這個接口,其中這兩個ConcreteObserver類的Update方法簽名必須與CreditCard中的事件SendMoney一致,不然就沒法註冊到CreditCard。server

public interface IObserver<T>
    {
        void Update(Object sender, T e);
    }

    public class SMSNotify : IObserver<CreditCard>
    {
        public void Update(Object sender, CreditCard e)
        {
            Console.WriteLine("Sms notify.Spend {0}", e.SpendAmount);
        }
    }

    public class Account : IObserver<CreditCard>
    {
        private float _accountAmount;

        public Account(float accountAmount)
        {
            _accountAmount = accountAmount;
        }

        public void Update(Object sender, CreditCard e)
        {
            _accountAmount += e.SpendAmount;
            Console.WriteLine("Account amount is {0}", _accountAmount);
        }
    }

最後看一下客戶端調用。對象

static void Main(string[] args)
    {
        CreditCard creditCard = new CreditCard();
        SMSNotify sms = new SMSNotify();
        Account account = new Account(1000);
        creditCard.SpendMoney += account.Update;
        creditCard.SpendMoney += sms.Update;
        creditCard.SpendAmount = 200;
    }
相關文章
相關標籤/搜索