引言
开弓没有回头箭,我们还的继续,回顾上一节我们讲的建造者模式,这节我们说说观察者模式。
示例地址
类图
定义
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
使用场景
1.关联行为场景,需要注意的是,关联行为是可拆分的,而不是"组合"关系;
2.事件多级触发场景;
3.跨系统的消息交换场景,例如消息队列、事件总线的处理机制。
观察者模式中的两个角色
Observer: 观察者角色。
Observable:被观察者角色。
观察者模式示例
举个栗子,我们在上班的时候,每个公司或者每个楼都有烟感设备,一旦抽烟或者楼道发生火灾,第一立刻鸣警,第二,装备里面的水银自断,立刻喷水。这个例子中,观察者是烟感设备,被观察者是烟或者火。
1. 定义观察者接口
/**
* 观察者接口
*
* @author 512573717@qq.com
* @created 2018/7/18 上午10:38.
*/
public interface IObserver {
//更新消息
void updateMessage(String message);
}
2. 观察者的实现(烟感应器)
/**
* 烟感应器
*
* @author 512573717@qq.com
* @created 2018/7/18 上午11:05.
*/
public class YanObserver implements IObserver {
@Override
public void updateMessage(String message) {
System.out.println(message + "烟感应器 感应到了火情,立刻鸣警");
}
}
3. 观察者的实现(水银感应器)
/**
* 水银感应器
*
* @author 512573717@qq.com
* @created 2018/7/18 上午11:08.
*/
public class ShuiYinObserver implements IObserver {
@Override
public void updateMessage(String message) {
System.out.println(message + "水银感应器 感应到了火情,立刻自毁水银,开始喷水");
}
}
4. 被观察者接口
/**
* 被观察者接口
*
* @author 512573717@qq.com
* @created 2018/7/18 上午10:39.
*/
public interface IObservable {
//添加
void addObserver(IObserver observer);
//移除
void removeObserver(IObserver observer);
//通知
void noticeObserver(String messgae);
}
5. 被观察者实现(着火)
/**
* 发生火情
*
* @author 512573717@qq.com
* @created 2018/7/18 上午11:23.
*/
public class ZhaoHuo implements IObservable {
private List<IObserver> mIObservers = new ArrayList<>();
@Override
public void addObserver(IObserver observer) {
if (!mIObservers.contains(observer)) {
mIObservers.add(observer);
}
}
@Override
public void removeObserver(IObserver observer) {
if (mIObservers.contains(observer)) {
mIObservers.remove(observer);
}
}
@Override
public void noticeObserver(String messgae) {
for (IObserver observer : mIObservers) {
observer.updateMessage(messgae);
}
}
public void change(String messgae) {
System.out.println("推模型---------");
noticeObserver(messgae);
}
}
6. Client调用
ZhaoHuo zhaoHuo = new ZhaoHuo();
//烟感设备
IObserver yanObserver = new YanObserver();
IObserver shuiYinObserver = new ShuiYinObserver();
//添加观察者
zhaoHuo.addObserver(yanObserver);
zhaoHuo.addObserver(shuiYinObserver);
//通知
zhaoHuo.change("着火了 !");
推模型和拉模型概念
在观察者模式中,又分为推模型和拉模型两种方式。
1. 推模型
主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
2. 拉模型
主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。
推模型和拉模型二者的比较
1、推模型是假定目标对象知道观察者需要的数据;拉模型不知道observer需要什么数据,因此把自身传给observer,由观察者来取值
2、推模型使observer对象难以复用,拉模型传递的是目标对象本身,满足各种需要
拉模型的示例
上面那个烟感设备就是典型的推模型,下面我们来看看拉模型的实现
1. 观察者接口(这里主要讲参数变成被观察者本身了)
/**
* 观察者接口
*
* @author 512573717@qq.com
* @created 2018/7/18 上午10:38.
*/
public interface IObserver {
//更新消息
void updateMessage(IObservable observable);
}
2.烟感应器
/**
* 烟感应器
*
* @author 512573717@qq.com
* @created 2018/7/18 上午11:05.
*/
public class YanObserver implements IObserver {
@Override
public void updateMessage(IObservable observable) {
String message=((ZhaoHuo)observable).getMessage();
System.out.println(message + "烟感应器 感应到了火情,立刻鸣警");
}
}
3. 水银感应器
/**
* 水银感应器
*
* @author 512573717@qq.com
* @created 2018/7/18 上午11:08.
*/
public class ShuiYinObserver implements IObserver {
@Override
public void updateMessage(IObservable observable) {
String message=((ZhaoHuo)observable).getMessage();
System.out.println(message + "水银感应器 感应到了火情,立刻自毁水银,开始喷水");
}
}
4. 被观察者接口(通知中不传递任何参数)
/**
* 被观察者接口
*
* @author 512573717@qq.com
* @created 2018/7/18 上午10:39.
*/
public interface IObservable {
//添加
void addObserver(IObserver observer);
//移除
void removeObserver(IObserver observer);
//通知
void noticeObserver();
}
5. 发生火情(自身作为参数传递)
/**
* 发生火情
*
* @author 512573717@qq.com
* @created 2018/7/18 上午11:23.
*/
public class ZhaoHuo implements IObservable {
private String message;
private List<IObserver> mIObservers = new ArrayList<>();
@Override
public void addObserver(IObserver observer) {
if (!mIObservers.contains(observer)) {
mIObservers.add(observer);
}
}
@Override
public void removeObserver(IObserver observer) {
if (mIObservers.contains(observer)) {
mIObservers.remove(observer);
}
}
@Override
public void noticeObserver() {
for (IObserver observer : mIObservers) {
// 将自身作为参数传递
observer.updateMessage(this);
}
}
public void change(String message) {
message = message;
System.out.println(" 拉模型:" + message);
//状态发生改变,通知各个观察者
this.noticeObserver();
}
public String getMessage() {
return message;
}
}
6. Client
ZhaoHuo zhaoHuo = new ZhaoHuo();
//烟感设备
IObserver yanObserver = new YanObserver();
IObserver shuiYinObserver = new ShuiYinObserver();
//添加观察者
zhaoHuo.addObserver(yanObserver);
zhaoHuo.addObserver(shuiYinObserver);
//通知
zhaoHuo.change("着火了 !");
总结
观察者模式定义的是一对多的依赖关系,一个被观察者可以拥有多个观察者,并且通过接口对观察者与被观察者进行逻辑解耦,降低二者的直接耦合。
1. 针对观察者与被观察者分别定义接口,有利于分别进行扩展。
2. 定义观察者集合,并定义针对集合的添加、删除操作,用于增加、删除订阅者(观察者
3. 定义通知方法,用于将新情况通知给观察者用户(订阅者用户)
4、观察者中需要有个接收被观察者通知的方法。
网友评论