日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

小看--发布-订阅(观察者)模式

發布時間:2025/6/17 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小看--发布-订阅(观察者)模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? (一)什么是觀察者模式

? ? ? ?發布-訂閱,這兩個詞語是對觀察者的最好解釋,現實生活中,這樣的案例有很多,比如在籃球比賽過程中教練,喊一個暫停,然后球員和裁判都做相關的響應,還有比如OA里面發布的放假通知等等。無論是籃球比賽,還是OA的通知,都存在一個角色,它的作用就是保持對相關問題的關注,在問題發生變化的時候,是Ta把消息通知給相關各方。觀察者模式也差不多這樣,它抽象一類對象(觀察者)專門負責"盯著"目標對象,當目標對象狀態有變動的時候,每個觀察者就會獲得通知并迅速做出響應,觀察者模式解決的也是調用通知關系所帶來的依賴。

? ? ? ? 上面的概念是比較官方的,我喜歡用自己的語言來講解,比如現實生活中的,蝴蝶效應,我們程序里面的,下訂單,就要發短信,減少庫存呀,等等一系列的連鎖反應,一句話,就是某個人發出一個行為,會引起一系列的連鎖反應。

? ? ?( 二 ) 一個簡單的案例

? ? ? ?南美洲亞馬孫河邊熱帶雨林中的蝴蝶,偶爾扇幾下翅膀,就有可能在兩周后引起美國得克薩斯的一場龍卷風。原因在于:蝴蝶翅膀的運動,導致其身邊的空氣系統發生變化,并引起微弱氣流的產生,而微弱氣流的產生又會引起它四周空氣? ? ? ? ?或其他系統產生相應變化,由此引起連鎖反應,最終導致其他系統的極大變化。“蝴蝶效應”聽起來有點荒誕,但說明了事物發展的結果,對初始條件具有極為敏感的依賴性;初始條件的極小偏差,將會引起結果的極大差異。這就是蝴蝶效應,下面我們用程序來模擬整個過程。

? ? ? ?假設蝴蝶煽動翅膀,可以引起雞飛狗跳,老鼠出洞,天氣變化,颶風形成。

/// <summary>/// 蝴蝶/// 假設蝴蝶煽動翅膀,可以引起雞飛狗跳,老鼠出洞,天氣變化,颶風形成/// </summary>public class ButterFly {/// <summary>/// 蝴蝶起飛/// </summary>public void Fly(){Console.WriteLine("蝴蝶起飛啦");Console.WriteLine("---------------產生連鎖反應---------------");new Chicken().Fly();new Dog().Jump();new Mouse().GoOut();new Weather().Change();new Wind().Generate();Console.WriteLine("---------------蝴蝶效應結束---------------");}}

? ? ? 這就是我們蝴蝶類,它起飛會造成這么多影響,會和這么多類產生關聯(耦合太高了)。如果有一天說要增加一個老虎上山了呢,或者說要移除一個,或者說改變一下順序,現在我們就要改變我們的蝴蝶類。我們來分析造成這個的原因是為啥呢,因為這個類違法了單一職責的原則,蝴蝶飛就可以了,那為啥還要去管飛完之后產生的連鎖反應呢,那行我們知道了這個就是不穩定的原因,那接下來開始我們的耍鍋套路,把不是自己的東西丟出去,做好自己的事情就可以了。

? ? ?那怎么丟呢,我們都應該要開發一個接口給別人添加關聯進來, 因為這里邊有很多類,并且都沒有啥關聯,所以只能才有一個接口,把他們都聯系起來。所以我們接下來定義一個接口IObserver,讓雞,狗,天氣等等類實現這個接口。

public interface IObserver{void Action();}

? ? ?雞類

public class Chicken:IObserver {public void Fly(){Console.WriteLine("雞雞起飛了");}public void Action(){Fly();}}

? ? ?當所有類實現這個接口的時候,我們就可以在蝴蝶類里面這樣定義了;先給定義一個集合和添加觀察者的方法,用來存儲觀察者的集合。? ??

private List<IObserver> _objServers=new List<IObserver>();public void AddObserver(IObserver item){this._objServers.Add(item);}/// <summary>/// 蝴蝶起飛/// </summary>public void Fly(){foreach (var obj in _objServers){obj.Action();}}

? ? ? 我們在客戶端調用呢

ButterFly butterFly=new ButterFly();butterFly.AddObserver(new Chicken());butterFly.AddObserver(new Dog());butterFly.AddObserver(new Mouse());butterFly.AddObserver(new Weather());butterFly.AddObserver(new Wind());butterFly.Fly();

? ? ?可能很多同學還是會說,這里還是有依賴,對確實的,但是我們把依賴交給了上游,上游改變不會影響下游,也就是蝴蝶類。

? ? ?從上面這個例子,我們看出觀察者模式,有三個東西,第一:引起連鎖反應的類(主題) 第二:有一個接口,實現了這個接口都是可以成為觀察者的,第三:觀察者。

? ? (三)觀察者模式的演變

? ? ? ? 下面請看代碼。有三個類,A,B,C想接收來自X的消息,簡單的說X發生變化,他們也跟著變化。

public class A {public int Data;public void Update(int data) {this.Data = data;}}public class B {public int Count; public void NotifyCount(int data) { this.Count = data; } } public class C { public int N; public void Set(int data) { this.N = data; } } //上面這三個類,類A,B,C是希望獲得X通知的類型 public class X { private int data; public A InstanceA; public B InstanceB; public C InstanceC; public void SetData(int data) { this.data = data; InstanceA.Update(data); InstanceB.NotifyCount(data); InstanceC.Set(data); } }
在我們調用的時候,應該這么做
A a = new A();B b = new B();C c = new C();X x = new X();x.InstanceA = a;x.InstanceB = b; x.InstanceC = c; x.SetData(10); Console.WriteLine("x發出消息了"); Console.WriteLine(a.Data); Console.WriteLine(b.Count); Console.WriteLine(c.N); 對于上面這種做法,大家應該都會。下面是這個上面例子的類圖關系,從這里,我們可以看得X和太多類直接關聯了。已經很不符合面向對象的設計原則了。

? ? ? ? 經過觀察,我們發現類A,B,C都有個共同之處,都是有一個類似于更新的方法,如果對他們進行抽象的話呢,就可以讓類X僅僅依賴于一個抽象的類型。下面直接看代碼

public interface IUpdatableObject {int Data {get;}void Update(int newData);}public class A : IUpdatableObject {private int data;public int Data { get { return this.data; } } public void Update(int newData) { this.data = newData; } } public class B : IUpdatableObject { private int data; public int Data { get { return this.data; } } public void Update(int newData) { this.data = newData; } } public class C : IUpdatableObject { private int data; public int Data { get { return this.data; } } public void Update(int newData) { this.data = newData; } } public class X { private IUpdatableObject[] objects = new IUpdatableObject[3]; //這個是索引器的用法 public IUpdatableObject this[int index] { set { objects[index] = value; } } private int data; public void Update(int newData) { this.data = newData; foreach(IUpdatableObject obj in objects) { obj.Update(newData); } } }

//調用代碼如下
X x = new X();IUpdatableObject a = new A();IUpdatableObject b = new B();IUpdatableObject c = new C();x[0] = a;x[1] = b; x[2] = c; x.Update(10); Console.WriteLine("x發出了消息"); Console.Write(a.Data); Console.Write(b.Data); Console.Write(c.Data);

通過上面我們就可以依賴于抽象了,比如當我們要新增加一個訂閱者的時候,也不用去類X里面改內部代碼,請看類圖。

? ? ?下面開始我們的版本的三;

先看看這幅圖,以后我們把消息的發布者,叫做主題,接收著叫做觀察者。主題類似于前文的X類,觀察者類似于A,B,C類。

? ? ?第二版本的時候,我們已經解決了兩個對象之間的松耦合,關于觀察者的一切,主題只需要知道他實現了哪個接口(前文中的IUpdatableObject接口),只要是實現了這個接口的,主題就會把他認為是觀察者。

? ???繼續這觀察者模式的發展和演變,到了我們第三個版本的觀察者模式。到了這步,我們想到如果有觀察者要退出,不訂閱這個主題了,等等操作(當主題發生變化的時候,,我們應該怎么做)。根據我們的面向對象的經驗,我們應該很容易想到應該把主題對象也要抽象化。

? ? ?

? ? ? ??

public interface ISubject {int Data { get; set; } //這個Data就是類似于用來發送消息的。/// <summary>/// 追加/// </summary>/// <param name="obs"></param>void Attach(IObserver obs);/// <summary>/// 刪除/// </summary>/// <param name="obs"></param>void Detach(IObserver obs);/// <summary>/// 監聽/// </summary>void Notify();}public interface IObserver {int Data { get; set; }void Update(int n);}public class ConcreteSubjectA : ISubject {public int Data { get; set; }public List<IObserver> ObsList = new List<IObserver>();public void Attach(IObserver obs) {Console.WriteLine("添加觀察者成功");ObsList.Add(obs);}public void Detach(IObserver obs) {Console.WriteLine("刪除觀察者成功");ObsList.Remove(obs);}public void Notify() {foreach(var obs in ObsList) {obs.Update(this.Data);}}}public class ConcreteObserverA : IObserver {public int Data { get; set; }public void Update(int n) {this.Data = n;}}public class ConcreteObserverB : IObserver {public int Data { get; set; }public void Update(int n) {this.Data = n;}}public class ConcreteObserverC : IObserver {public int Data { get; set; }public void Update(int n) {this.Data = n;}} ISubject csA = new ConcreteSubjectA();IObserver a = new ConcreteObserverA();IObserver b = new ConcreteObserverB();IObserver c = new ConcreteObserverC();csA.Attach(a);csA.Attach(b);csA.Attach(c);csA.Data = 20;//移除觀察者csA.Detach(b);csA.Notify();//我們現在做的這個版本相對于上一個版本就是增加了對觀察者的管理。//以及我們可以讓我們的程序都是依賴于抽象。Console.WriteLine($"類A的數據為:{a.Data}");Console.WriteLine($"類B的數據為{b.Data}");Console.WriteLine($"類C的數據為{c.Data}"); 降到這里基本上把觀察者模式給講完了,我更加喜歡叫做發布訂閱模式,這樣更加好理解。

? ? ? 我們上面的那個例子還可以在抽象一點,利用泛型類和泛型方法來做,真正的達到抽象。下面是最終版本的實現代碼(把泛型類和泛型方法用上),這個大家可以思考下怎么做?相關代碼暫時不貼出來先。?

? ? ? 最后,希望大家能夠帶帶我這個菜鳥,謝謝各位。

? ? ??

轉載于:https://www.cnblogs.com/gdouzz/p/6955825.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的小看--发布-订阅(观察者)模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 黄视频在线免费看 | 成人免费版 | 色撸撸在线视频 | 欧美日韩第一页 | av网站亚洲| av性色| 亚洲国产精品二区 | 中文字幕日本人妻久久久免费 | 超碰人人艹| 免费啪啪小视频 | 在线色av| 欧美一级二级三级视频 | 亚州中文字幕 | 午夜精品无码一区二区三区 | 玖玖999| 777片理伦片在线观看 | 俄罗斯精品一区二区三区 | 日韩中文字幕在线观看视频 | 国产女主播av | 国产精品99久久久久久久 | 大地资源中文在线观看免费版 | 国产99色| 韩日一区二区三区 | 一区二区在线看 | 波多野结衣中文字幕在线 | 少妇免费直播 | 欧美精品韩国精品 | h片在线免费看 | 精品国产乱码久久久久久郑州公司 | 极品销魂美女一区二区三区 | 91成人品 | 最新视频在线观看 | 国产乱色精品成人免费视频 | 日韩中文字幕电影 | 免费啪啪小视频 | 国产毛片毛片毛片毛片毛片毛片 | 综合久| av5566| 黄色亚洲网站 | 国产精品亚洲αv天堂无码 伊人性视频 | 国内自拍一区 | www.日韩.com | 亚洲区综合 | 国产午夜小视频 | 嫩草影院在线免费观看 | 美女视频黄色在线观看 | 日本少妇一区二区三区 | 一级肉体全黄裸片中国 | 免费看黄在线看 | 香蕉小视频| 精品欧美一区二区三区 | 欧美在线观看视频一区 | 欧洲色综合| 无码精品人妻一区二区三区湄公河 | 日韩h在线观看 | 人妻互换一区二区三区四区五区 | 午夜精品久久久久久久91蜜桃 | 96久久精品 | 久草资源网| 57pao国产成永久免费视频 | 在线电影一区二区三区 | 亚洲1级片| 成人精品一区二区三区视频 | 人妻久久一区二区三区 | 色戒在线免费 | 亚洲人成人一区二区在线观看 | 国产精品久久久久久免费观看 | 亚洲综合自拍偷拍 | 亚洲一区免费在线观看 | 免费三级网站 | 明里柚番号 | 日本一级片在线观看 | 国产一级片免费在线观看 | 福利资源在线 | 三级黄色免费 | 国产剧情av引诱维修工 | 干欧美 | 久久免费播放 | www.精品| 老版水浒传83版免费播放 | 一级黄色片网站 | 亚洲综合国产精品 | 毛茸茸日本熟妇高潮 | 天天碰天天| 日韩国产欧美视频 | 131美女爱做视频 | 依依综合网 | 欧美激情性做爰免费视频 | 国产小视频在线看 | 日韩欧美一二三 | 一级二级三级黄色片 | 91精彩刺激对白 | 韩国美女视频在线观看18 | 国产精品jizz在线观看无码 | 亚洲影库 | 激情小说视频在线 | 少妇人妻偷人精品视频蜜桃 | 男男一级淫片免费播放 | 黑人精品无码一区二区三区AV |