日韩性视频-久久久蜜桃-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位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

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

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

主站蜘蛛池模板: 99视频热| 亚洲永久精品一区 | 精品一区二区中文字幕 | 欧美一区二区三区婷婷月色 | 特级性生活片 | 色片免费看 | 三级视频在线观看 | 97一区二区三区 | 日韩电影三级 | 性猛交xxxx乱大交孕妇印度 | 五月激情四射网 | 欧美午夜网 | 免费久久久久久 | 国产精品一区二区亚洲 | 激情av一区 | 中国av毛片| 国产成人无码a区在线观看视频 | 日本福利片在线观看 | 好吊操av | av男人的天堂在线 | 国产精品欧美精品 | 亚洲综合一区二区 | 亚洲成人一区二区在线观看 | 欧美精品免费一区二区 | 亚州av| 国产综合精品视频 | 在线精品一区二区三区 | 97视频资源| 香蕉久久精品日日躁夜夜躁 | 久久96 | 国产极品美女在线 | 丁香亚洲| 9999视频 | 色蜜桃av| 黄色一级在线 | 欧美毛片网站 | 大乳丰满人妻中文字幕日本 | 国产一级片av| 欧美成人午夜 | 免费av成人| av作品在线观看 | 久久精品99 | 97在线精品视频 | 怡红院毛片 | 视频三区在线 | 成人区人妻精品一区 | 午夜精品福利在线观看 | 女同性做爰三级 | 天天干天天操天天干 | 午夜h | 日日摸日日碰夜夜爽av | 老女人黄色片 | 一区免费| 亚洲一区二区免费在线观看 | 国产三级在线播放 | 自偷自拍亚洲 | 亚洲yy | 极品白嫩的小少妇 | 欧美日韩精品电影 | 制服 丝袜 激情 欧洲 亚洲 | 99自拍偷拍视频 | 国家队动漫免费观看在线观看晨光 | 在线色播 | 公车乳尖揉捏酥软呻吟 | 一边摸一边做爽的视频17国产 | 黄色九九 | 亚洲欧美中文日韩在线 | 香蕉视频在线看 | 88av网| 亚洲一区二区中文 | 天天爽| 熟妇高潮喷沈阳45熟妇高潮喷 | 国产一级18片视频 | 国产美女视频一区二区 | 美女爽爽爽 | 假日游船法国满天星 | 五月天激情在线 | 中国一级黄色 | www三级免费 | 人人干人人艹 | 第一福利在线视频 | 操操操av| 亚洲中文字幕视频一区 | julia一区二区三区中文字幕 | 丰满尤物白嫩啪啪少妇 | 国产www在线 | 91网在线 | 精品人伦一区二区三区 | 日韩美女福利视频 | 在线观看免费国产 | 午夜视频网站在线观看 | 性工作者十日谈 | 午夜视频日韩 | 激情五月婷婷综合网 | www.99精品| 综合网五月 | 久久天| 亚洲一区二区中文 | av视屏在线 |