C#設計模式——觀察者模式(Observer Pattern)


一、概述
在軟件設計工作中會存在對象之間的依賴關系,當某一對象發生變化時,所有依賴它的對象都需要得到通知。如果設計的不好,很容易造成對象之間的耦合度太高,難以應對變化。使用觀察者模式可以降低對象之間的依賴,以松耦合的方式實現這一目標。
二、觀察者模式
觀察者模式定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並自動更新。其結構圖如下:

Subject知道它的所有觀察者並提供了觀察者注冊和刪除訂閱的接口。
Observer為那些在目標發生改變時需獲得通知的對象定義一個更新接口。
ConcreteSubject實現Subject接口,當改變狀態時向依賴於它的ConcreteObserver發送通知。
ConcreteObserver實現Observer的更新接口,使得自身能根據ConcreteSubject狀態的不同而做出相應的改變。
觀察者模式分為推模式和拉模式兩種。推模式是當有通知時,把依賴對象的信息以參數的形式傳遞給所有觀察者,而拉模式通知方法本身並不帶任何的參數,是由觀察者自己到依賴對象那里取回相關信息。在推模式下,所有觀察者都通過參數傳遞的方式得到依賴對象的全部信息,與依賴對象之間的耦合較低,但不能實現“按需所取”所需要信息的。而拉模式僅僅是通知觀察者,至於要不要提取依賴對象的信息則是觀察者自己的事情,這么一來就實現“按需所取”,但往往要在ConcreteObserver里保存一個ConcreteSubject的引用,與ConcreteSubject的耦合也加強了。
觀察者模式的Subject一般需要提供觀察者注冊和刪除訂閱的接口,但在.NET中,往往可以利用事件和委托的特性來實現觀察者模式,這是一種更為優雅的方案。
三、示例
我們現在利用事件實現觀察者模式。我們設計一個信用卡消費的簡單例子,在消費的同時需要對用戶賬戶進行扣款,同時對用戶進行短信提醒。
首先定義信用卡類,當消費金額變動時會觸發Notify方法通知該對象的所有觀察者。

View Code
 1     public class CreditCard : EventArgs
 2     {
 3         private float _spendAmount;
 4         public event EventHandler<CreditCard> SpendMoney;
 5 
 6         public float SpendAmount
 7         {
 8             get
 9             {
10                 return _spendAmount;
11             }
12             set
13             {
14                 _spendAmount = value;
15                 Notify();
16             }
17         }
18 
19         private void Notify()
20         {
21             if (SpendMoney != null)
22             {
23                 SpendMoney(this, this);
24             }
25         }
26     }

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

View Code
 1    public interface IObserver<T>
 2     {
 3         void Update(Object sender, T e);
 4     }
 5 
 6     public class SMSNotify : IObserver<CreditCard>
 7     {
 8         public void Update(Object sender, CreditCard e)
 9         {
10             Console.WriteLine("Sms notify.Spend {0}", e.SpendAmount);
11         }
12     }
13 
14     public class Account : IObserver<CreditCard>
15     {
16         private float _accountAmount;
17 
18         public Account(float accountAmount)
19         {
20             _accountAmount = accountAmount;
21         }
22 
23         public void Update(Object sender, CreditCard e)
24         {
25             _accountAmount += e.SpendAmount;
26             Console.WriteLine("Account amount is {0}", _accountAmount);
27         }
28     }

最后看一下客戶端調用。

View Code
1     static void Main(string[] args)
2     {
3         CreditCard creditCard = new CreditCard();
4         SMSNotify sms = new SMSNotify();
5         Account account = new Account(1000);
6         creditCard.SpendMoney += account.Update;
7         creditCard.SpendMoney += sms.Update;
8         creditCard.SpendAmount = 200;
9     } 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM