更新时间:2018年12月07日11时50分 来源:传智播客 浏览次数:
---
typora-root-url: pics
---
# 设计模式之观察者模式
## 概述
观察者模式,有时又被称为模型-视图(View)模式,有的叫发布-订阅模式,监听模式或从属者模式,是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。一般通过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
## 重要的角色
1. 观察者: 观察目标对象的状态、行为等的的主体。观察将自己存放到被观察对象中,被观察对象将观察者存放在一个容器(Vector)里。
2. 被观察的对象:被观察者所研究或关注的对象。当被观察的对象发生了某种变化时,将循环遍历容器中的所有观察者,并将发生的变化通知予观察者。
## 观察者模式结构图
![observer_structure](/observer_structure.png)
### 说明
* Observable 是一个接口,定义了被观察者主体所具备的方法,实现这个接口的主体可以拥有多个观察者,当主体对象的状态发生改变时,可以通知到所有的观察者
* addObserver: 添加新的观察者
* delObserver: 移除原有的观察者
* notifyObservers: 当主体对象发生改变时,通知所有的观察者
* Observer 也是一个接口,定义了观察者所具备的方法,当主体发生变化时,通过调用update方法通知观察者,你观察的主体发生了变化
* ConcreteSubject 是Observable的具体实现类,被观察的对象,也可称为观察的实 "物"
* ConcreteObserver 是Observer的实现类,实现这个接口的就是观察者,可以实现对实 “物” 的观察
## 举例
我们都知道微信有个叫公众号的服务,只要公众号发布新的消息,关注了这个公众的微信用户就能收最新的消息,如果用户取消了该公众号的关注,就不再收到由该公众号发布出来的消息了。
## 分析
这里的微信公众号可以看成是一个 被观察对象,即观察的对象,而关注了这个公众号的所有用户都是观察者
下面我们可以通过代码来简单模拟一下
## 代码实现
### 1. 创建普通宇博娱乐在线注册不了工程
![project](/project.png)
### 2. Observer
```宇博娱乐在线注册不了
package com.itheima.demo;
/**
* 观察者接口
*/
public interface Observer {
/**
* 被观察体发生变化时调用的方法,用来通知观察者
* @param args
*/
void update(Object args);
/**
* 获取观察者名称
* @return
*/
String getName();
}
```
### 3. Observable
```宇博娱乐在线注册不了
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
```宇博娱乐在线注册不了
package com.itheima.demo;
import 宇博娱乐在线注册不了.util.Vector;
/**
* 被观察者,微信公众号
*
*/
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() + " 关注了公众号 " + 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--) {
// 通知每个观察者
arr[i].update(args);
}
}
/**
* 发布新的消息
* @param message
*/
public void postMessage(String message) {
System.out.println(name + "微信公众号发布新的消息: " + message);
notifiyObservers(message);
}
}
```
### 5. WeChatUser
```宇博娱乐在线注册不了
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 测试
```宇博娱乐在线注册不了
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("改变中国IT教育,我们正在行动...");
}
}
```
### 7. 运行结果
![result](/result.png)
## 总结
优点:观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者并不认识任何一个具体观察者,当发生变化时,只需要调用它们共有的接口方法就可以了。
缺点:
* 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
* 如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。
* 如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的
* 虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但无法知道这个变化的过程