偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

一文帶你徹底搞懂發(fā)布與訂閱設(shè)計(jì)

開發(fā) 前端
我們常說的發(fā)布訂閱設(shè)計(jì)模式,也叫觀察者模式,也就是事件監(jiān)聽機(jī)制,觀察者模式訂閱了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,當(dāng)這個(gè)主題對(duì)象發(fā)生改變時(shí),會(huì)通知所有的觀察者對(duì)象,使他們能夠自動(dòng)的更新自己!

[[415483]]

本文轉(zhuǎn)載自微信公眾號(hào)「Java極客技術(shù)」,作者鴨血粉絲 。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。

一、介紹

我們常說的發(fā)布訂閱設(shè)計(jì)模式,也叫觀察者模式,也就是事件監(jiān)聽機(jī)制,觀察者模式訂閱了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,當(dāng)這個(gè)主題對(duì)象發(fā)生改變時(shí),會(huì)通知所有的觀察者對(duì)象,使他們能夠自動(dòng)的更新自己!

一個(gè)軟件系統(tǒng)要求某個(gè)對(duì)象在發(fā)生變化時(shí),某些其他的對(duì)象作出相應(yīng)的改變,能做到這點(diǎn)的設(shè)計(jì)方案有很多,但觀察者模式是滿足這一要求的各種設(shè)計(jì)方案中最重要的一種。

從整體來看,觀察者模式所涉及的角色有:

  • 抽象主題角色:抽象主題角色把所有對(duì)觀察者對(duì)象的引用保存在一個(gè)集合中,每個(gè)主題都可以有任意數(shù)量的觀察者。抽象主題提供一個(gè)接口,可以增加和刪除觀察者對(duì)象;
  • 具體主題角色:將有關(guān)狀態(tài)存入具體觀察者對(duì)象,在具體主題的內(nèi)部狀態(tài)改變時(shí),給所有登記過的觀察者發(fā)出通知;
  • 抽象觀察者角色:為所有的具體觀察者提供一個(gè)接口,在得到主題通知時(shí)更新自己;
  • 具體觀察者角色:存儲(chǔ)與主題的狀態(tài)相關(guān)的狀態(tài)。具體觀察者角色實(shí)現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài)協(xié)調(diào)

廢話也不多說了,下面我們直接講案例!

二、示例

抽象主題角色,有增加觀察者、刪除觀察者、通知觀察者的功能,內(nèi)容如下:

  1. public abstract class AbstractSubject { 
  2.  
  3.     /** 用來保存注冊(cè)的觀察者對(duì)象 */ 
  4.     private List<Observer> list = new ArrayList<Observer>(); 
  5.  
  6.     /** 
  7.      * 注冊(cè)觀察者對(duì)象 
  8.      */ 
  9.     public void add(Observer observer){ 
  10.         list.add(observer); 
  11.         System.out.println("add an observer"); 
  12.     } 
  13.  
  14.     /** 
  15.      * 刪除觀察者對(duì)象 
  16.      * @param observer 
  17.      */ 
  18.     public void remove(Observer observer){ 
  19.         list.remove(observer); 
  20.         System.out.println("delete an observer"); 
  21.     } 
  22.  
  23.     /** 
  24.      * 通知所有注冊(cè)的觀察者對(duì)象 
  25.      * @param state 
  26.      */ 
  27.     public void notifyObservers(String state){ 
  28.         for (int i = 0; i < list.size(); i++) { 
  29.             list.get(i).update(state); 
  30.         } 
  31.     } 

具體主題角色,這個(gè)change方法放在子類中是因?yàn)榭赡懿煌闹黝}在改變觀察者狀態(tài)的時(shí)候會(huì)做一些不同的操作,因此就不統(tǒng)一放在父類Subject里面了,內(nèi)容如下:

  1. public class ConcreteSubject extends AbstractSubject{ 
  2.  
  3.     private String state; 
  4.  
  5.     public void change(String newState){ 
  6.         state = newState; 
  7.         System.out.println("主題狀態(tài):" + state); 
  8.  
  9.         //狀態(tài)發(fā)生改變,通知所有的觀察者 
  10.         super.notifyObservers(state); 
  11.     } 

觀察者接口,內(nèi)容如下:

  1. public interface Observer { 
  2.  
  3.     /** 
  4.      * 修改狀態(tài) 
  5.      * @param state 
  6.      */ 
  7.     void update(String state); 

具體觀察者實(shí)現(xiàn)了觀察者接口,內(nèi)容如下:

  1. public class ConcreteObserver implements Observer{ 
  2.  
  3.     @Override 
  4.     public void update(String state) { 
  5.         System.out.println("觀察者,收到狀態(tài):" + state); 
  6.     } 

客戶端調(diào)用代碼,一旦主題調(diào)用了change方法改變觀察者的狀態(tài),那么觀察者Observer里面的observerState全都改變了,內(nèi)容如下:

  1. public class ObserverClient { 
  2.  
  3.     public static void main(String[] args) { 
  4.         //創(chuàng)建一個(gè)主題角色 
  5.         ConcreteSubject subject = new ConcreteSubject(); 
  6.  
  7.         //創(chuàng)建觀察者對(duì)象 
  8.         ConcreteObserver observer = new ConcreteObserver(); 
  9.  
  10.         //將觀察者加入主題對(duì)象上 
  11.         subject.add(observer); 
  12.  
  13.         //改變主題狀態(tài) 
  14.         subject.change("hello world"); 
  15.     } 

運(yùn)行結(jié)果如下:

  1. add an observer 
  2. 主題狀態(tài):hello world 
  3. 觀察者,收到狀態(tài):hello world 

這里只添加了一個(gè)觀察者,有興趣的可以試試看多添加幾個(gè)觀察者,效果都是一樣的,主題角色改變狀態(tài),觀察者狀態(tài)全變。

三、應(yīng)用

觀察者模式的兩種模型

  • 推模型:主題對(duì)象向觀察者推送主題的詳細(xì)信息,不管觀察者是否需要。推送的信息通常是主題對(duì)象的全部或部分?jǐn)?shù)據(jù),上面的例子就是典型的推模型。
  • 拉模型:主題對(duì)象在通知觀察者的時(shí)候,只傳遞少量信息。如果觀察者需要更具體的信息,由觀察者主動(dòng)到主題對(duì)象中去獲取,相當(dāng)于是觀察者從主題對(duì)象中拉數(shù)據(jù)。一般這種模型的實(shí)現(xiàn)中,會(huì)把主題對(duì)象自身通過update()方法傳遞給觀察者,這樣觀察者在需要獲取數(shù)據(jù)的時(shí)候,就可以通過這個(gè)引用來獲取了。

兩種模型的比較

  • 1、推模型是假設(shè)主題對(duì)象知道觀察者需要的數(shù)據(jù),拉模型是假設(shè)主題對(duì)象不知道觀察者需要什么數(shù)據(jù),干脆把自身傳遞過去,讓觀察者自己按需要取值。
  • 2、推模型可能會(huì)使得觀察者對(duì)象難以復(fù)用,因?yàn)橛^察者的update()方法是按需要定義的參數(shù),可能無法兼顧到?jīng)]有考慮到的使用情況,這意味著出現(xiàn)新的情況時(shí),可能要提供新的update()方法。

JDK是有直接支持觀察者模式的,就是java.util.Observer這個(gè)接口,內(nèi)容如下:

  1. public interface Observer { 
  2.     /** 
  3.      * This method is called whenever the observed object is changed. An 
  4.      * application calls an <tt>Observable</tt> object's 
  5.      * <code>notifyObservers</code> method to have all the object's 
  6.      * observers notified of the change. 
  7.      * 
  8.      * @param   o     the observable object. 
  9.      * @param   arg   an argument passed to the <code>notifyObservers</code> 
  10.      *                 method. 
  11.      */ 
  12.     void update(Observable o, Object arg); 

這就是觀察者的接口,定義的觀察者只需要實(shí)現(xiàn)這個(gè)接口就可以了。update()方法,被觀察者對(duì)象的狀態(tài)發(fā)生變化時(shí),被觀察者的notifyObservers()方法就會(huì)調(diào)用這個(gè)方法,內(nèi)容如下:

  1. public class Observable { 
  2.     private boolean changed = false
  3.     private Vector obs; 
  4.     
  5.     /** Construct an Observable with zero Observers. */ 
  6.  
  7.     public Observable() { 
  8.     obs = new Vector(); 
  9.     } 
  10.  
  11.     /** 
  12.      * Adds an observer to the set of observers for this object, provided  
  13.      * that it is not the same as some observer already in the set.  
  14.      * The order in which notifications will be delivered to multiple  
  15.      * observers is not specified. See the class comment. 
  16.      * 
  17.      * @param   o   an observer to be added. 
  18.      * @throws NullPointerException   if the parameter o is null
  19.      */ 
  20.     public synchronized void addObserver(Observer o) { 
  21.         if (o == null
  22.             throw new NullPointerException(); 
  23.     if (!obs.contains(o)) { 
  24.         obs.addElement(o); 
  25.     } 
  26.     } 
  27.     ... 

這是被觀察者的父類,也就是主題對(duì)象。這是一個(gè)線程安全的類,是基于Vector實(shí)現(xiàn)的。

創(chuàng)建一個(gè)觀察者,內(nèi)容如下:

  1. import java.util.Observable; 
  2. import java.util.Observer; 
  3.  
  4. public class Watched implements Observer { 
  5.  
  6.     @Override 
  7.     public void update(Observable o, Object arg) { 
  8.         System.out.println("觀察者,收到狀態(tài):" + arg); 
  9.     } 

創(chuàng)建一個(gè)主題,內(nèi)容如下:

  1. import java.util.Observable; 
  2.  
  3. public class Subject extends Observable { 
  4.  
  5.     private String data; 
  6.  
  7.     public void setData(String newData){ 
  8.         System.out.println("主題狀態(tài):" + newData); 
  9.         data = newData; 
  10.         setChanged(); 
  11.         notifyObservers(data); 
  12.     } 

寫一個(gè)main函數(shù)調(diào)用,內(nèi)容如下:

  1. public class WatchedClient { 
  2.  
  3.     public static void main(String[] args) { 
  4.         //創(chuàng)建觀察者對(duì)象 
  5.         Watched watched = new Watched(); 
  6.  
  7.         //創(chuàng)建主題 
  8.         Subject subject = new Subject(); 
  9.  
  10.         //將觀察者對(duì)象加入主題 
  11.         subject.addObserver(watched); 
  12.  
  13.         //修改主題狀態(tài) 
  14.         subject.setData("hello world"); 
  15.  
  16.     } 

運(yùn)行結(jié)果,內(nèi)容如下:

  1. 主題狀態(tài):hello world 
  2. 觀察者,收到狀態(tài):hello world 

看到主題對(duì)象改變的時(shí)候,觀察者對(duì)象的狀態(tài)也隨之改變。

四、總結(jié)

引入設(shè)計(jì)模式最主要的作用我認(rèn)為就是兩點(diǎn):

  • 去重復(fù)代碼,使得代碼更清晰、更易讀、更易擴(kuò)展
  • 解耦,使得代碼可維護(hù)性更好,修改代碼的時(shí)候可以盡量少改地方

使用觀察者模式可以很好地做到這兩點(diǎn)。增加觀察者,直接new出觀察者并注冊(cè)到主題對(duì)象之后就完事了,刪除觀察者,主題對(duì)象調(diào)用方法刪除一下就好了,其余都不用管。主題對(duì)象狀態(tài)改變,內(nèi)部會(huì)自動(dòng)幫我們通知每一個(gè)觀察者,是不是很方便呢?

觀察者模式主要應(yīng)用場(chǎng)景有:

 

  • 對(duì)一個(gè)對(duì)象狀態(tài)的更新需要其他對(duì)象同步更新
  • 對(duì)象僅需要將自己的更新通知給其他對(duì)象而不需要知道其他對(duì)象的細(xì)節(jié),如消息推送

 

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2021-06-30 08:45:02

內(nèi)存管理面試

2020-03-18 14:00:47

MySQL分區(qū)數(shù)據(jù)庫

2022-06-07 10:13:22

前端沙箱對(duì)象

2020-12-07 06:19:50

監(jiān)控前端用戶

2021-07-08 10:08:03

DvaJS前端Dva

2023-03-06 21:29:41

mmap技術(shù)操作系統(tǒng)

2020-05-11 14:35:11

微服務(wù)架構(gòu)代碼

2023-10-27 08:15:45

2020-01-02 09:57:09

Redis訂閱發(fā)布

2024-10-16 10:11:52

2021-11-06 10:18:30

Python變量常量

2019-11-06 17:30:57

cookiesessionWeb

2021-08-31 07:02:20

Diff算法DOM

2023-12-15 09:45:21

阻塞接口

2023-12-12 07:31:51

Executors工具開發(fā)者

2024-08-08 14:57:32

2022-04-11 10:56:43

線程安全

2021-09-07 09:46:40

JavaScriptGenerator函數(shù)

2021-09-11 10:41:27

PythonPickle模塊

2023-05-22 13:27:17

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)