作业三_C#中的观察者模式解析
作業三_C#中的觀察者模式解析
?
?
一、觀察者模式的理解分析
由于之前沒有接觸過觀察者模式,所以找了一段源碼編譯運行調試一下。下面是觀察者模式用C#模擬實現的示意源碼。該段代碼模擬了觀察者模式的一個運行原理,其可以觀察到被觀察對象的動態。(你已經設置好的想看到的動態。)
下面是代碼源碼和注釋以及運行過程:
?
示例代碼:
?
1 using System; 2 using System.Collections; 3 namespace CSharp_Observe 4 { 5 class Program 6 { 7 // Fields 8 private ArrayList observers = new ArrayList(); //在program類中定義一個動態私有數組 取名observers 9 // Methods 10 public void Attach(Observer observer) 11 { 12 observers.Add(observer); //在該類中定義添加功能 給私有成員observes添加內容 13 } 14 public void Detach(Observer observer) 15 { 16 observers.Remove(observer); //在該類中定義移除功能 給私有成員observes移除內容 17 } 18 public void Notify() 19 { 20 foreach (Observer o in observers) //遍歷該數組 每次都執行更新 21 o.Update(); 22 } 23 } 24 class ConcreteSubject : Program // 繼承了Program類 25 { 26 // Fields 27 private string subjectState; 28 // Properties 29 public string SubjectState 30 { 31 get { return subjectState; } 32 set { subjectState = value; } 33 } 34 } 35 // "Observer" 36 abstract class Observer 37 { 38 // Methods 39 abstract public void Update(); //定義抽象方法 觀察者 40 } 41 // "ConcreteObserver" 42 class ConcreteObserver : Observer 43 { 44 // Fields 45 private string name; 46 private string observerState; 47 private ConcreteSubject subject; 48 // Constructors 49 public ConcreteObserver(ConcreteSubject subject, 50 string name) 51 { 52 this.subject = subject; 53 this.name = name; 54 } 55 // Methods 56 override public void Update() 57 { 58 observerState = subject.SubjectState; 59 Console.WriteLine("Observer {0}'s new state is {1}", 60 name, observerState); 61 } 62 // Properties 63 public ConcreteSubject Subject 64 { 65 get { return subject; } 66 set { subject = value; } 67 } 68 } 69 public class Client 70 { 71 public static void Main(string[] args) 72 { 73 // 先聲明出基礎的數據 以及初始化操作 74 ConcreteSubject s = new ConcreteSubject(); 75 s.Attach(new ConcreteObserver(s, "1")); 76 s.Attach(new ConcreteObserver(s, "2")); 77 s.Attach(new ConcreteObserver(s, "3")); 78 // 改變s 并且通知觀察者 也就是調用函數 Notify 79 s.SubjectState = "ABC"; 80 s.Notify(); 81 Console.ReadKey(); 82 } 83 } 84 } 上圖運行代碼及其注釋解析。?
?
? ? ? 從這段程序以及查閱資料了解到,觀察者模式的含義是:定義對象間一種一對多的依賴關系,是的沒當一個對象改變狀態,則所有依賴于它的對象都會得到通知并自動更新。
比如其中的發布訂閱模式,發布者發布信息,訂閱者獲取信息,訂閱了就能收到信息,沒訂閱就收不到信息改變狀態。(這里其實可以做到當一個狀態改變時,另一個狀態也跟著改變,為編程提供了很大的方便)
? ? ? 一個軟件系統常常要求在某一個對象的狀態發生變化的時候,某些其它的對象做出相應的改變。做到這一點的設計方案有很多,但是為了使系統能夠易于復用,應該選擇低耦合度的設計方案。減少對象之間的耦合有利于系統的復用,但是同時設計師需要使這些低耦合度的對象之間能夠維持行動的協調一致,保證高度的協作(Collaboration)。觀察者模式是滿足這一要求的各種設計方案中最重要的一種。
通過查閱資料了解到觀察者模式一般有以下幾種角色:
? ? ? ?抽象主題(Subject):它把所有觀察者對象的引用保存到一個聚集里,每個主題都可以有任何數量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象。
??具體主題(ConcreteSubject):將有關狀態存入具體觀察者對象;在具體主題內部狀態改變時,給所有登記過的觀察者發出通知。
??抽象觀察者(Observer):為所有的具體觀察者定義一個接口,在得到主題通知時更新自己。
??具體觀察者(ConcreteObserver):實現抽象觀察者角色所要求的更新接口,以便使本身的狀態與主題狀態協調。
?
二,實例解析觀察者模式:
? ? ? 每種編程架構及程序語言,對觀察者模式都有不通的具體實現。在.NET框架中,C#語言使用委托以及事件,可以很好的實現觀察者模式。委托相當于“訂閱清單”的角色,當目標中關聯了該委托的事件被觸發時,則委托將自動按序執行觀察者注冊于委托中的方法。
? ? ? 模型需要做的只是聲明委托以及聲明委托類型的事件。當然,還可以附加上封裝了觸發委托事件的方法。所有派生自模型的類都是具體目標,它們所要做的只是在適當的場合觸發事件。(即發出“通知”)。
? ? ? 通過對模型與觀察者基類的分析可知,委托與事件的機制幾乎消除了這兩個模塊之間的耦合,靈活性提高了很多。如果需要增加觀察者,則只需要覆蓋基類抽象方法及把觀察目標傳遞給基類。
具體示例:
?
1、首先是建立模型,把目標基類建立好。
?
2、建立觀察者基類,在這里分為單行為和多行為的。
2.1 首先是單行為基類的建立。
?
1 /**//// <summary> 2 /// 在Observer Pattern(觀察者模式)中,此類作為所有Observer(觀察者)的抽象基類 3 /// 所有要充當觀察者的類(在此事例中為"老鼠"和"人")都繼承于此類. 4 /// 我們說此類作為觀察者基類,用于規劃所有觀察者(即訂閱方)訂閱行為. 5 /// 在此事例中,規劃了針對目標基類(ModelBase)中聲明的"無參無返回"委托的一個 6 /// 方法(Response),并于構造該觀察者時將其注冊于具體目標(參數傳遞)的委托事件中. 7 /// 具體實施過程: 8 /// 1.指定觀察者所觀察的對象(即發布方).(通過構造器傳遞) 9 /// 2.規劃觀察者自身需要作出響應方法列表 10 /// 3.注冊需要委托執行的方法.(通過構造器實現) 11 /// </summary> 12 public abstract class Observer 13 { 14 /**//// <summary> 15 /// 構造時通過傳入模型對象,把觀察者與模型關聯,并完成訂閱. 16 /// 在此確定需要觀察的模型對象. 17 /// </summary> 18 /// <param name="childModel">需要觀察的對象</param> 19 public Observer(ModelBase childModel) 20 { 21 //訂閱 22 //把觀察者行為(這里是Response)注冊于委托事件 23 childModel.SubEvent+=new ModelBase.SubEventHandler(Response); 24 } 25 26 /**//// <summary> 27 /// 規劃了觀察者的一種行為(方法),所有派生于該觀察者基類的具體觀察者都 28 /// 通過覆蓋該方法來實現作出響應的行為. 29 /// </summary> 30 public abstract void Response(); 31 } 單行為基類的建立?
2.2、多行為基類的建立。
?
1 /**//// <summary> 2 /// 定義了另一個觀察者基類.該觀察者類型擁有兩個響應行為. 3 /// 并在構造時將響應行為注冊于委托事件. 4 /// (具體描述請參照另一觀察者基類Observer) 5 /// </summary> 6 public abstract class Observer2 7 { 8 /**//// <summary> 9 /// 構造時通過傳入模型對象,把觀察者與模型關聯,并完成訂閱. 10 /// 在此確定需要觀察的模型對象. 11 /// </summary> 12 /// <param name="childModel">需要觀察的對象</param> 13 public Observer2(ModelBase childModel) 14 { 15 //訂閱 16 //把觀察者行為(這里是Response和Response2)注冊于委托事件 17 childModel.SubEvent+=new ModelBase.SubEventHandler(Response); 18 childModel.SubEvent+=new ModelBase.SubEventHandler(Response2); 19 20 } 21 /**//// <summary> 22 /// 規劃了觀察者的二種行為(方法),所有派生于該觀察者基類的具體觀察者都 23 /// 通過覆蓋該方法來實現作出響應的行為. 24 /// </summary> 25 public abstract void Response(); 26 public abstract void Response2(); 27 } 多行為基類的建立?
3、建立具體的目標。
?
1 /**//// <summary> 2 /// 此類為觀察者模式中的具體目標(即具體發布方),其繼承于模型. 3 /// 其中包含(調用)了在模型中被封裝好的觸發委托事件的方法. 4 /// </summary> 5 public class Cat : ModelBase 6 { 7 public Cat() 8 { 9 } 10 /**//// <summary> 11 /// 定義了貓的一種行為----大叫 12 /// </summary> 13 public void Cry() 14 { 15 System.Console.WriteLine("Cat Cry.."); 16 //調用了觸發委托事件的方法. 17 //通知委托開始執行觀察者已訂閱的方法. 18 this.Notify(); 19 } 20 } 建立具體的目標4、建立具體的觀察者。
? 4.1具體觀察者1 老鼠
?
1 /**//// <summary> 2 /// 此類為觀察者模式中的具體觀察者(即具體發布方),其繼承于觀察者基類. 3 /// 其中覆蓋了觀察者基類規劃好的方法,實現了響應的具體行為. 4 /// </summary> 5 public class Mouse : Observer 6 { 7 /**//// <summary> 8 /// 觀察者可以擁有自己的成員(字段或者方法). 9 /// 在此事例中增加了"老鼠的名字" 10 /// </summary> 11 private string name; 12 /**//// <summary> 13 /// 構造時確定觀察者所需要觀察的對象(具體目標),并傳遞給觀察者基類構造器, 14 /// 實現響應行為(方法)的訂閱.另外,為觀察者實例初始化成員. 15 /// </summary> 16 /// <param name="name">老鼠的名字</param> 17 /// <param name="childModel"> 18 /// 需要觀察的對象(發布方). 19 /// 此處用模型基類來傳遞,是為了兼容所有派生于此模型的觀察者,從而提高擴展性. 20 /// </param> 21 public Mouse(string name, ModelBase childModel) : base(childModel) 22 { 23 //初始化字段(老鼠的名字) 24 this.name=name; 25 } 26 /**//// <summary> 27 /// 覆蓋了該類觀察者需要作出的具體響應行為. 28 /// 此行為已在觀察者基類中注冊于委托事件,由委托事件調度執行,不需要直接調用. 29 /// </summary> 30 public override void Response() 31 { 32 //具體響應內容 33 System.Console.WriteLine(this.name+"開始逃跑"); 34 } 35 36 } 具體觀察者14.2建立具體觀察者2? 主人
?
1 /**//// <summary> 2 /// 此類為觀察者模式中的具體觀察者(即具體發布方),其繼承于觀察者基類. 3 /// 其中覆蓋了觀察者基類規劃好的方法,實現了響應的具體行為. 4 /// </summary> 5 public class Master : Observer 6 { 7 /**//// <summary> 8 /// 構造時確定觀察者所需要觀察的對象(具體目標),并傳遞給觀察者基類構造器, 9 /// 實現響應行為(方法)的訂閱. 10 /// </summary> 11 public Master(ModelBase childModel) : base(childModel) 12 { 13 } 14 15 /**//// <summary> 16 /// 覆蓋了該類觀察者需要作出的具體響應行為. 17 /// 此行為已在觀察者基類中注冊于委托事件,由委托事件調度執行,不需要直接調用. 18 /// </summary> 19 public override void Response() 20 { 21 System.Console.WriteLine("主人醒來"); 22 } 23 } 具體觀察者24.3建立具體觀察者3 孩子
?
1 /**//// <summary> 2 /// 此類為觀察者模式中的具體觀察者(即具體發布方),其繼承了訂閱了2個響應行為的 3 /// 觀察者基類. 4 /// 其中覆蓋了觀察者基類規劃好的二個方法,實現了響應的具體行為. 5 /// </summary> 6 public class Master2 : Observer2 7 { 8 /**//// <summary> 9 /// 構造時確定觀察者所需要觀察的對象(具體目標),并傳遞給觀察者基類構造器, 10 /// 實現響應行為(方法)的訂閱. 11 /// </summary> 12 public Master2(ModelBase childBase) : base(childBase) 13 { 14 } 15 16 /**//// <summary> 17 /// 覆蓋了該類觀察者需要作出的具體響應行為. 18 /// 此行為已在觀察者基類中注冊于委托事件,由委托事件調度執行,不需要直接調用. 19 /// </summary> 20 public override void Response() 21 { 22 Console.WriteLine("baby醒來。。。。"); 23 24 } 25 /**//// <summary> 26 /// 覆蓋了該類觀察者需要作出的另一個響應行為. 27 /// </summary> 28 public override void Response2() 29 { 30 Console.WriteLine("開始哭鬧。。。。。"); 31 } 32 } 具體觀察者35、最終運行測試。 main函數代碼。
?
1 static void Main(string[] args) 2 { 3 4 //聲明并實例化一個目標(即發布方)對象----貓 5 Cat myCat = new Cat(); 6 //聲明并實例化一個Mouse類型的觀察者對象--名叫mouse1的老鼠.并把那只貓作為它所要觀察的對象. 7 Mouse myMouse1 = new Mouse("mouse1", myCat); 8 //類似地生成另一只名叫mouse2的老鼠(觀察者),把同一只貓作為它的觀察的對象. 9 Mouse myMouse2 = new Mouse("mouse2", myCat); 10 //聲明并實例化一個Master類型的觀察者--主人,并同時把那只貓也作為他的觀察對象. 11 Master myMaster = new Master(myCat); 12 //聲明并實例化一個Master2類型的觀察者--寶寶,同時把那只貓也 13 Master2 myLittleMaster = new Master2(myCat); 14 15 //貓大叫,并觸發了委托事件,從而開始按順序調用觀察者已訂閱的方法. 16 myCat.Cry(); 17 18 Console.Read(); 19 } 測試代碼?
?三、分析觀察者模式所帶來的好處。
?
觀察者模式的效果有以下幾個優點:
(1)由于被觀察者和觀察者沒有緊密地耦合在一起,因此它們可以屬于不同的抽象化層次。如果被觀察者和觀察者都被扔到一起,那么這個對象必然跨越抽象化和具體化層次。
(2)觀察者模式支持廣播通信。被觀察者會向所有的登記過的觀察者發出通知。觀察者可以自動地獲取到想要觀察對象變化信息,用以做出響應和調整。
觀察者模式有下面的一些缺點:
? ? ? 如果一個被觀察者對象有很多直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。雖然觀察者模式可以隨時使觀察者知道所觀察的對象發生了變化,但是觀察者模式沒有相應的機制使觀察者知道所觀察的對象是怎么發生變化的。
?四、總結
? ? ? 實際上在C#中實現Observer模式沒有這么辛苦,.NET中提供了Delegate與Event機制,我們可以利用這種機制簡化Observer模式。關于Delegate與Event的使用方法請參考相關文檔。就可以對Observer進行改進。
Observer模式的優點是實現了表示層和數據邏輯層的分離,并定義了穩定的更新消息傳遞機制,類別清晰,并抽象了更新接口,使得可以有各種各樣不同的表示層(觀察者)。
但是其缺點是每個外觀對象必須繼承這個抽像出來的接口類,這樣就造成了一些不方便,比如有一個別人寫的外觀對象,并沒有繼承該抽象類,或者接口不對,我們又希望不修改該類直接使用它。會造成更加復雜煩瑣的設計,增加出錯幾率。
五、參考資料
https://blog.csdn.net/cjolj/article/details/56482467?utm_source=blogxgwz17
http://www.cnblogs.com/zhenyulu/articles/73723.html
?https://www.cnblogs.com/xmfdsh/p/4047114.html
?六、代碼GitHub地址
1.上述文章第一個例子地址:https://github.com/jaymayi/test/blob/master/Program.cs
2.上述文章實例觀察者模式的例子地址:https://github.com/jaymayi/test/blob/master/Program2.cs
3.燒水例子參考:https://github.com/jaymayi/test/blob/master/Class1.cs
轉載于:https://www.cnblogs.com/liuduoduo/p/9836070.html
總結
以上是生活随笔為你收集整理的作业三_C#中的观察者模式解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上传项目到gitHub,上传报错和删除g
- 下一篇: 「LibreOJ Round #6」花火