教育行業(yè)A股IPO第一股(股票代碼 003032)

全國(guó)咨詢/投訴熱線:400-618-4000

java設(shè)計(jì)模式之觀察者模式

更新時(shí)間:2018年12月07日11時(shí)50分 來(lái)源:傳智播客 瀏覽次數(shù):

---

typora-root-url: pics

---

# 設(shè)計(jì)模式之觀察者模式

## 概述

? 觀察者模式,有時(shí)又被稱(chēng)為模型-視圖(View)模式,有的叫發(fā)布-訂閱模式,監(jiān)聽(tīng)模式或從屬者模式,是軟件設(shè)計(jì)模式的一種。在此種模式中,一個(gè)目標(biāo)物件管理所有相依于它的觀察者物件,并且在它本身的狀態(tài)改變時(shí)主動(dòng)發(fā)出通知。一般通過(guò)呼叫各觀察者所提供的方法來(lái)實(shí)現(xiàn)。此種模式通常被用來(lái)實(shí)現(xiàn)事件處理系統(tǒng)。

## 重要的角色

1. 觀察者: 觀察目標(biāo)對(duì)象的狀態(tài)、行為等的的主體。觀察將自己存放到被觀察對(duì)象中,被觀察對(duì)象將觀察者存放在一個(gè)容器(Vector)里。

2. 被觀察的對(duì)象:被觀察者所研究或關(guān)注的對(duì)象。當(dāng)被觀察的對(duì)象發(fā)生了某種變化時(shí),將循環(huán)遍歷容器中的所有觀察者,并將發(fā)生的變化通知予觀察者。

## 觀察者模式結(jié)構(gòu)圖

![observer_structure](/observer_structure.png)

### 說(shuō)明

* Observable 是一個(gè)接口,定義了被觀察者主體所具備的方法,實(shí)現(xiàn)這個(gè)接口的主體可以擁有多個(gè)觀察者,當(dāng)主體對(duì)象的狀態(tài)發(fā)生改變時(shí),可以通知到所有的觀察者

* addObserver: 添加新的觀察者

* delObserver: 移除原有的觀察者

* notifyObservers: 當(dāng)主體對(duì)象發(fā)生改變時(shí),通知所有的觀察者

* Observer 也是一個(gè)接口,定義了觀察者所具備的方法,當(dāng)主體發(fā)生變化時(shí),通過(guò)調(diào)用update方法通知觀察者,你觀察的主體發(fā)生了變化

* ConcreteSubject 是Observable的具體實(shí)現(xiàn)類(lèi),被觀察的對(duì)象,也可稱(chēng)為觀察的實(shí) "物"

* ConcreteObserver 是Observer的實(shí)現(xiàn)類(lèi),實(shí)現(xiàn)這個(gè)接口的就是觀察者,可以實(shí)現(xiàn)對(duì)實(shí) “物” 的觀察

## 舉例

? 我們都知道微信有個(gè)叫公眾號(hào)的服務(wù),只要公眾號(hào)發(fā)布新的消息,關(guān)注了這個(gè)公眾的微信用戶就能收最新的消息,如果用戶取消了該公眾號(hào)的關(guān)注,就不再收到由該公眾號(hào)發(fā)布出來(lái)的消息了。

## 分析

? 這里的微信公眾號(hào)可以看成是一個(gè) 被觀察對(duì)象,即觀察的對(duì)象,而關(guān)注了這個(gè)公眾號(hào)的所有用戶都是觀察者

? 下面我們可以通過(guò)代碼來(lái)簡(jiǎn)單模擬一下

## 代碼實(shí)現(xiàn)

### 1. 創(chuàng)建普通java工程

? ![project](/project.png)

### 2. Observer

```java

package com.itheima.demo;

/**

* 觀察者接口

*/

public interface Observer {

/**

* 被觀察體發(fā)生變化時(shí)調(diào)用的方法,用來(lái)通知觀察者

* @param args

*/

void update(Object args);

/**

* 獲取觀察者名稱(chēng)

* @return

*/

String getName();

}

```

### 3. Observable

```java

package com.itheima.demo;

/**

* 被觀察者接口

*

*/

public interface Observable {

/**

* 添加觀察者

* @param observer

*/

void addObserver(Observer observer);

/**

* 解除觀察者

* @param observer

*/

void delObserver(Observer observer);

/**

* 通知所有的觀察者

*/

void notifiyObservers(Object args);

}

```

### 4. WeChatOfficialAccount

```java

package com.itheima.demo;

import java.util.Vector;

/**

* 被觀察者,微信公眾號(hào)

*

*/

public class WeChatOfficialAccount implements Observable {

private String name;

/**

* 保存所有的觀察者

*/

private Vector observers;

public WeChatOfficialAccount(String name) {

this.name = name;

observers = new Vector();

}

@Override

public synchronized void addObserver(Observer observer) {

System.out.println(observer.getName() + " 關(guān)注了公眾號(hào) " + this.name);

this.observers.add(observer);

}

@Override

public synchronized void delObserver(Observer observer) {

observers.remove(observer);

}

@Override

public void notifiyObservers(Object args) {

Observer[] arr = observers.toArray(new Observer[] {});

for(int i = arr.length - 1; i >= 0; i--) {

// 通知每個(gè)觀察者

arr[i].update(args);

}

}

/**

* 發(fā)布新的消息

* @param message

*/

public void postMessage(String message) {

System.out.println(name + "微信公眾號(hào)發(fā)布新的消息: " + message);

notifiyObservers(message);

}

}

```

### 5. WeChatUser

```java

package com.itheima.demo;

/**

* 微信用戶

*

*/

public class WeChatUser implements Observer {

private String username;

public WeChatUser(String username) {

this.username = username;

}

@Override

public void update(Object args) {

readMessage((String)args);

}

public void readMessage(String message) {

System.out.println(String.format("%s 讀取了信息-> %s", this.username,message));

}

@Override

public String getName() {

return this.username;

}

}

```

### 6. DemoMain 測(cè)試

```java

package com.itheima.demo;

public class DemoMain {

public static void main(String[] args) {

WeChatOfficialAccount wechat = new WeChatOfficialAccount("傳智播客");

WeChatUser wechatUser = new WeChatUser("張三");

wechat.addObserver(wechatUser);

wechatUser = new WeChatUser("李四");

wechat.addObserver(wechatUser);

wechatUser = new WeChatUser("王五");

wechat.addObserver(wechatUser);

wechat.postMessage("改變中國(guó)IT教育,我們正在行動(dòng)...");

}

}

```

### 7. 運(yùn)行結(jié)果

? ![result](/result.png)

## 總結(jié)

優(yōu)點(diǎn):觀察者模式在被觀察者和觀察者之間建立一個(gè)抽象的耦合。被觀察者并不認(rèn)識(shí)任何一個(gè)具體觀察者,當(dāng)發(fā)生變化時(shí),只需要調(diào)用它們共有的接口方法就可以了。

缺點(diǎn):

* 如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間

* 如果在被觀察者之間有循環(huán)依賴的話,被觀察者會(huì)觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,導(dǎo)致系統(tǒng)崩潰。

* 如果對(duì)觀察者的通知是通過(guò)另外的線程進(jìn)行異步投遞的話,系統(tǒng)必須保證投遞是以自恰的方式進(jìn)行的

* 雖然觀察者模式可以隨時(shí)使觀察者知道所觀察的對(duì)象發(fā)生了變化,但無(wú)法知道這個(gè)變化的過(guò)程java

0 分享到:
和我們?cè)诰€交談!