Java设计模式(三)——观察者模式和监听器
为了实现多个模块之间的联动,最好的方法是使用观察者模式。网上介绍的资料也比较多,今天我就从另一个方面谈谈自己对观察者模式的理解。从JDK提供的支持库里,我们能够找到四个对象:Observable、Observer、EventListener、EventObject。
先模拟一个后台处理过程:
import java.util.Observable;
public class Subject extends Observable {
private int value;
public int getValue() {
return value;
}
private void progress() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
value = i;
setChanged(); // 值发生改变
notifyObservers(); // 调用所有注册的观察者
}
}
public void onStart() {
progress();
}
}
稍微对上面的代码做一些解释,顺便介绍一下Observable这个类:
顾名思义“能够被观察的对象”,用户能够继承它并增加自己的定义,它提供了几个方法。
addObserver(Observer o):注册观察者,这个方法的内部其实就是提供了一个队列。将多有观察者储存在队列中,当有事件发生的时候遍历这个队列。
hasChanged()与setChanged():当事件发生时,需要调用setChanged()方法,此时hasChanged()返回true否则返回false。
notifyObservers()与notifyObservers(Object arg):通知所有观察者可以获取各自需要的变量或只推送某个对象。
下面模拟一个进度条:
public class Progress implements Observer {
private int value;
@Override
public void update(Observable o, Object arg) {
value = ((Subject)o).getValue();
System.out.print("#");
}
public static void main(String[] args) {
Progress ui = new Progress();
Subject subject = new Subject();
subject.addObserver(ui);
subject.onStart();
}
}
进度条作为后台程序的观察者需要实现update(Observable o, Object arg)方法。当Subject调用setChanged()后使用notifyObservers()方法会回调update。需要注意,notifyObservers方法隐式调用clearChanged(),因此如果用户试图在update方法中调用o.hasChanged()的时候,只会返回false。
我们再来看一个使用监听器的例子。相对上面的代码来说,实现自己的监听器会稍微复杂一些。但是只要我们先想清楚逻辑就不会有什么难度。
监听器模式将对象分为了三个模块:Source(事件源)、ChangeEvent(事件)、StatusListener(监听器)。事件源可能会触发多个事件,针对不同的事件都可以定义独立的监听器,当事件源触发事件的时候监听器获得通知并实现用户自定义的业务逻辑。相比Observer和Observable的二元实现来说。监听器抽象了事件对象,目的是不同的事件源可能包含相同的触发事件,为了提供更好的内聚处理。监听器的处理逻辑是针对事件本身而言的。
那么也许你会好奇,如果监听的对象是事件本身如何根据不同的事件源提供不同的逻辑呢?秘诀在于事件本身会提供一个事件源对象供监听器判断。
或许现在你反而会更加困惑。不要紧其实当我第一次自己去实现监听器的时候面对这三个模块的逻辑也相当混乱,等你看完代码以后再回来仔细推敲上面的文字会豁然开朗。
先看一下事件源:
public class Source {
private List<StatusListener> statusListeners = new ArrayList<>();
public void addStatusListener(StatusListener listener) {
statusListeners.add(listener);
}
public void onClick() {
ChangeEvent event = new ChangeEvent(this);
event.setStatus("click");
notifyListener(event);
}
public void onDoubleClick() {
ChangeEvent event = new ChangeEvent(this);
event.setStatus("doubleClick");
notifyListener(event);
}
public void onMove() {
ChangeEvent event = new ChangeEvent(this);
event.setStatus("move");
notifyListener(event);
}
private void notifyListener(ChangeEvent event) {
Iterator<StatusListener> it = statusListeners.iterator();
while(it.hasNext()) {
StatusListener listener = it.next();
listener.changeStatus(event);
}
}
}
事件源提供了三个触发事件,分别是点击(click)、双击(doubleclick)、拖拽(move)。这是设计UI的时候经常遇到的三个事件,相信大家不应该陌生。Source没有继承任何接口或父类,完全是一个自定义的类。那么针对三种触发类型,我们接下来需要提供事件。
public class ChangeEvent extends EventObject {
private String status;
public ChangeEvent(Object source) {
super(source);
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
ChangeEvent对象继承EventObject,必须提供一个注册事件源的构造方法。然后在事件中,我们定义了一个字符串变量作为保存状态的接口,更加复杂的逻辑原理也是一样的。
定义好事件以后,我们再定义一个监听器接口。
public interface StatusListener extends EventListener {
void changeStatus(ChangeEvent event);
}
EventListener接口仅仅是一个标志性接口,内部没有做任何处理。所有逻辑都由使用者自己实现。我们就定义一个changeStatus方法,要求提供ChangeEvent作为参数。
最后返回Source类,添加一个测试用的main方法
public static void main(String[] args) {
Source source = new Source();
source.addStatusListener(new StatusListener(){
@Override
public void changeStatus(ChangeEvent event) {
System.out.println(event.getStatus());
}
});
source.onClick();
source.onDoubleClick();
source.onMove();
}
在main方法中我们能够观察到一些区别,首先,监听器并没有提供默认的addListener方法。我们需要自己创建一个保存所有监听对象的队列。
其次,也没有提供notifyListener方法,为了触发监听器我们也需要自己实现遍历队列的逻辑。
最后说一下我对以上两种模式区别的理解。
Observable和Observer属于对象驱动或值驱动。例如进度条的例子,UI界面需要时刻观察后台进度的变化从而动态更新自己。这里的关键词是动态更新。
EventListener和EventObject属于事件驱动或方法驱动。例如按钮的例子,用户造成了某个事件,立刻触发后台程序的响应。这里的关键词是响应。
Java设计模式(三)——观察者模式和监听器的更多相关文章
- 理解java设计模式之观察者模式
在生活实际中,我们经常会遇到关注一个事物数据变化的情况,例如生活中的温度记录仪,当温度变化时,我们观察它温度变化的曲线,温度记录日志等.对于这一类问题,很接近java设计模式里面的“观察者模式”,它适 ...
- java设计模式之观察者模式以及在java中作用
观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式.模型-视图(Model/View)模式.源-监听器(Source/Listener)模式或从属者(Dependen ...
- java设计模式02观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 这里主要讲一下学习内置观察者的记录,在JA ...
- java设计模式之观察者模式
观察者模式 观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式.模型-视图(View)模式.源-收听者(Listener)模式或从属者模式)是软件设计模式的一种.在此种模 ...
- JAVA设计模式 之 观察者模式
简介: 观察者模式是JDK中最多的设计模式之一,非常有用,观察者模式介绍了一对多的依赖关系及松耦合,有了观察者,你将会消息灵通. 认识观察者模式,看一个报纸.杂志订阅是怎么回事: (1). 报社的业务 ...
- 折腾Java设计模式之观察者模式
观察者模式 Define a one-to-many dependency between objects where a state change in one object results in ...
- JAVA设计模式之观察者模式 - Observer
有趣的事情发生时,可千万别错过了!有一个模式可以帮你的对象知悉现况,不会错过该对象感兴趣的事.对象甚至在运行时可决定是否要继续被通知.有了观察者,你将会消息灵通. 介绍 观察者模式的定义: 在对象之间 ...
- JAVA设计模式 之 观察者模式(JDK内置实现)
简介:使用JAVA内置的帮你搞定观察者模式. 1. 先把类图放在这里: (1). Observable类追踪所有的观察者,并通知他们. (2). Observer这个接口看起来很熟悉,它和我们之前写的 ...
- java设计模式之观察者模式(9)
Java观察者模式的浅析 简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象.这样一个主题对象在状态上的变化能够通知所有的依赖于此对象的那些观察者对象,使这些观察者 ...
- java设计模式:观察者模式
package Observer; public class Test { /** * client测试类别 * 观察者模式一般由四部分组成: * 1摘要观察员(教科书被称为一般"Subje ...
随机推荐
- OpenGL函数思考-glLoadIdentity
函数原型: void glLoadIdentity(void) 函数说明: OpenGL为我们提供了一个非常简单的恢复初始坐标系的手段,那就是调用glLoadIdentity()命令.该命令是一个无参 ...
- Linux一些零碎
1.设置时间和市区 1.tzselect 2.sudo cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
- ORM系列之二:EF(5) Model First
前面我们已经介绍过EF中Code First开发模式,简而言之,就是不管三七二十一直接写代码,不过对于很多开发人员来说,可能并不习惯这样来开发,并且安装标准的开发流程,应该是先建模再进行编码,当然EF ...
- iOS10新特性
1.Siri API 的开放自然是 iOS 10 SDK 中最激动人心也是亮眼的特性.Apple 加入了一套全新的框架 Intents.framework 来表示 Siri 获取并解析的结果. 在 i ...
- Bittorrent Protocol Specification v1.0 中文
翻译:小马哥 日期:2004-5-22 BitTorrent 是一种分发文件的协议.它通过URL来识别内容,并且可以无缝的和web进行交互.它基于HTTP协议,它的优势是:如果有多个下载者并发的下载同 ...
- iOS 将一串字符里面的某个字符全部标志出来
NSMutableString * mutStr = [NSMutableString stringWithString:@"aaabbbbaaaccc"]; NSString * ...
- margin重叠现象与margin auto自适应居中
上下相邻的(算一种兄弟关系)普通元素,上下边距并非简单的相加,而是取其中最大的边距值:而浮动的盒子边距是相加的:父子div也会发生重叠,并不是bug: <style>#test1{ wid ...
- ThinkPHP3.1快速入门(1)基础
学习网址:http://www.thinkphp.cn/document/60.html
- Git的.gitignore文件配置
.gitignore是Git工具的配置文件,用于屏蔽某些文件上传到线上. 创建.gitignore 在window系统中,不允许新建文件名以"."开头的文件,所以通过git bas ...
- yii框架的理解
Yii Framework是一个基于组件.用于开发大型 Web 应用的高性能 PHP 框架.Yii提供了今日Web 2.0应用开发所需要的几乎一切功能.Yii是最有效率的PHP框架之一. yii框架里 ...