设计模式笔记(19)---观察者模式(行为型)
Gof定義
定義對象間的一種一對多的依賴關系,以便當一個對象的狀態發生改變時,所有依賴于它的對象都得到通 知并自動更新
動機
在軟件構建過程中,我們需要為某些對象建立一種“通知依賴關系” ——一個對象(目標對象)的狀態發生改變,所有的依賴對象(觀察者對象)都將得到通知。如果這樣的依賴關系過于緊密,將使軟件不能很好地抵御變化。使用面向對象技術,可以將這種依賴關系弱化,并形成一種穩定的依賴關系。從而實現軟件體系結構的松耦合。
看這樣一個場景,銀行的ATM機在處理完成銀行賬戶的存入或取出后會給用戶發送手機短信和電子郵件,那么就會有這樣三個對象,BankAccount Emailer Mobile,代碼如下:
public class BankAccount {Emailer emailer;Mobile mobile;public void Withdraw(int data){ //處理存入或取出emailer.SendEmail("");mobile.SendMsg("");} } public class Emailer {public void SendEmail(string to){ //發送郵件} } public class Mobile {public void SendMsg(string phoneNumber){ //發送短信} }上面的代碼中BankAccount和Emailer Mobile之間有很強的依賴關系,Emailer和Mobile的變化會對BankAccount產生很大的影響,接下來要做的就是使BankAccount不要去依賴Emailer和Mobile這樣的具體類,而應該去依賴他們的抽象,抽象的東西通常是穩定的,這樣BankAccount和抽象之間的依賴就是一種比較弱的依賴關系,代碼如下:
public class UserAccountArgs {public string Email { get; set; }public string PhoneNumber { get; set; }public UserAccountArgs(string email, string phoneNumer){Email = email;PhoneNumber = phoneNumer;} } public interface IAccountObserver {void Update(UserAccountArgs args); } public class Emailer : IAccountObserver {public void Update(UserAccountArgs args){Console.WriteLine("消息已發送郵件至郵箱:" + args.Email);} } public class Mobile : IAccountObserver {public void Update(UserAccountArgs args){Console.WriteLine("消息已發短信至手機:" + args.PhoneNumber);} } public class BankAccount {List<IAccountObserver> list = new List<IAccountObserver>();public void Withdraw(int data){ //處理存入或取出if(data>0){Console.WriteLine("您的賬戶存入了"+data+"元");}else{Console.WriteLine("您的賬戶取出了" + Math.Abs(data) + "元");} UserAccountArgs args = new UserAccountArgs("oec2003@gmail.com","1388888****");foreach (IAccountObserver observer in list){observer.Update(args);}}public void AddObserver(IAccountObserver observer){list.Add(observer);}public void RemoveObserver(IAccountObserver observer){list.Remove(observer);} } /// <summary> /// 客戶端調用 /// </summary> class Program {static void Main(string[] args){BankAccount bankAccount = new BankAccount();bankAccount.AddObserver(new Emailer());bankAccount.AddObserver(new Mobile());bankAccount.Withdraw(-500);} }運行結果如下:
上面的改進代碼只是對Emailer和Mobile進行了抽象看,其實BankAccount也可能是不穩定的,所以也需要對BankAccount進行抽象,改進后的代碼如下:
public class UserAccountArgs {public string Email { get; set; }public string PhoneNumber { get; set; }public UserAccountArgs(string email, string phoneNumer){Email = email;PhoneNumber = phoneNumer;} } public interface IAccountObserver {void Update(UserAccountArgs args); } public class Emailer : IAccountObserver {public void Update(UserAccountArgs args){Console.WriteLine("消息已發送郵件至郵箱:" + args.Email);} } public class Mobile : IAccountObserver {public void Update(UserAccountArgs args){Console.WriteLine("消息已發短信至手機:" + args.PhoneNumber);} } public abstract class Subject {List<IAccountObserver> list = new List<IAccountObserver>();protected virtual void Notify(UserAccountArgs args){foreach (IAccountObserver observer in list){observer.Update(args);}}public void AddObserver(IAccountObserver observer){list.Add(observer);}public void RemoveObserver(IAccountObserver observer){list.Remove(observer);} } public class BankAccount:Subject { public void Withdraw(int data){ //處理存入或取出if(data>0){Console.WriteLine("您的賬戶存入了"+data+"元");}else{Console.WriteLine("您的賬戶取出了" + Math.Abs(data) + "元");} UserAccountArgs args = new UserAccountArgs("oec2003@gmail.com","1388888****");Notify(args);} } /// <summary> /// 客戶端調用 /// </summary> class Program {static void Main(string[] args){BankAccount bankAccount = new BankAccount();bankAccount.AddObserver(new Emailer());bankAccount.AddObserver(new Mobile());bankAccount.Withdraw(-500);} }這樣就成了將不穩定的對象進行抽象,最后相互依賴的是抽象與抽象之間的依賴,便于擴展。
觀察者模式的結構圖:
對比上圖和上面的代碼有以下的對應關系
- Subject:Subject
- Observer:IObserver
- ConcreteSubject:BankAccount
- ConcreteObserver:Emailer Mobile
基本代碼的實現:
public abstract class Subject {private List<Observer> list = new List<Observer>();/// <summary>/// 添加觀察者/// </summary>/// <param name="observer"></param>public void Attach(Observer observer){list.Add(observer);}/// <summary>/// 移除觀察者/// </summary>/// <param name="observer"></param>public void Detach(Observer observer){list.Remove(observer);}public void Notify(){foreach (Observer observer in list){observer.Update();}} } /// <summary> /// 抽象觀察者類 /// </summary> public abstract class Observer {public abstract void Update(); } /// <summary> /// 具體通知者 /// </summary> public class ConcreteSuject : Subject {public string SubjectState { get; set; }public ConcreteSuject(string subjectState){this.SubjectState = subjectState;} } /// <summary> /// 具體觀察者 /// </summary> public class ConcreteObserver : Observer {private ConcreteSuject _subject;private string _name;public ConcreteObserver(ConcreteSuject subject,string name){this._subject = subject;this._name = name;}public override void Update(){Console.WriteLine("觀察者:" + _name + "狀態為:" + _subject.SubjectState);} } /// <summary> /// 客戶端調用 /// </summary> class Program {static void Main(string[] args){ConcreteSuject cs1 = new ConcreteSuject("寫博客");ConcreteSuject cs2 = new ConcreteSuject("大籃球");cs1.Attach(new ConcreteObserver(cs1, "oec2003"));cs1.Attach(new ConcreteObserver(cs2, "oec2004"));cs1.Notify();} }?
Observer模式的幾個要點
- 使用面向對象的抽象,Observer模式使得我們可以獨立地改變目標與觀察者,從而使二者之間的依賴關系達致松耦合。
- 目標發送通知時,無需指定觀察者,通知(可以攜帶通知信息作為參數)會自動傳播。觀察者自己決定是否需要訂閱通知,目標對象對此一無所知。
- 在C#的event中,委托充當了抽象的Observer接口,而提供事件的對象充當了目標對象。委托是比抽象Observer接口更為松耦合的設計。
?
作者:oec2003(水杯)
出處:http://oec2003.cnblogs.com/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
轉載于:https://www.cnblogs.com/abenmao/archive/2012/05/25/2518034.html
總結
以上是生活随笔為你收集整理的设计模式笔记(19)---观察者模式(行为型)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nhibernate 3.0 cookb
- 下一篇: 程序2