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