为了实现多个模块之间的联动,最好的方法是使用观察者模式。网上介绍的资料也比较多,今天我就从另一个方面谈谈自己对观察者模式的理解。从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设计模式(三)——观察者模式和监听器的更多相关文章

  1. 理解java设计模式之观察者模式

    在生活实际中,我们经常会遇到关注一个事物数据变化的情况,例如生活中的温度记录仪,当温度变化时,我们观察它温度变化的曲线,温度记录日志等.对于这一类问题,很接近java设计模式里面的“观察者模式”,它适 ...

  2. java设计模式之观察者模式以及在java中作用

    观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式.模型-视图(Model/View)模式.源-监听器(Source/Listener)模式或从属者(Dependen ...

  3. java设计模式02观察者模式

    观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 这里主要讲一下学习内置观察者的记录,在JA ...

  4. java设计模式之观察者模式

    观察者模式 观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式.模型-视图(View)模式.源-收听者(Listener)模式或从属者模式)是软件设计模式的一种.在此种模 ...

  5. JAVA设计模式 之 观察者模式

    简介: 观察者模式是JDK中最多的设计模式之一,非常有用,观察者模式介绍了一对多的依赖关系及松耦合,有了观察者,你将会消息灵通. 认识观察者模式,看一个报纸.杂志订阅是怎么回事: (1). 报社的业务 ...

  6. 折腾Java设计模式之观察者模式

    观察者模式 Define a one-to-many dependency between objects where a state change in one object results in ...

  7. JAVA设计模式之观察者模式 - Observer

    有趣的事情发生时,可千万别错过了!有一个模式可以帮你的对象知悉现况,不会错过该对象感兴趣的事.对象甚至在运行时可决定是否要继续被通知.有了观察者,你将会消息灵通. 介绍 观察者模式的定义: 在对象之间 ...

  8. JAVA设计模式 之 观察者模式(JDK内置实现)

    简介:使用JAVA内置的帮你搞定观察者模式. 1. 先把类图放在这里: (1). Observable类追踪所有的观察者,并通知他们. (2). Observer这个接口看起来很熟悉,它和我们之前写的 ...

  9. java设计模式之观察者模式(9)

    Java观察者模式的浅析 简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象.这样一个主题对象在状态上的变化能够通知所有的依赖于此对象的那些观察者对象,使这些观察者 ...

  10. java设计模式:观察者模式

    package Observer; public class Test { /** * client测试类别 * 观察者模式一般由四部分组成: * 1摘要观察员(教科书被称为一般"Subje ...

随机推荐

  1. 安卓中級教程(7):annotation中的 public @interface的用法

    package com.example.ele_me.util; import java.lang.annotation.Retention; import java.lang.annotation. ...

  2. Java POI导入导出Excel

    1.异常java.lang.NoClassDefFoundError: org/apache/poi/UnsupportedFileFormatException 解决方法: 使用的poi的相关jar ...

  3. 【偶像大师 白金星光】的【Variable Tone】技术大公开!偶像从哪里看都那么可爱,VA小组谈制作方针

    http://game.watch.impress.co.jp/docs/news/1016369.html         自从街机版的运营依赖,今年迎来了[偶像大师]系列的11周年.在CEDEC ...

  4. PHP和HTML代码混合编译的三种方法

    第一种是在HTML中加PHP. 大段大段的html代码中,在各个需要执行php的地方<?php .... ?> 比如 line7-9: 1 <head> 2 <meta ...

  5. Spring IoC容器初始化过程学习

    IoC容器是什么?IoC文英全称Inversion of Control,即控制反转,我么可以这么理解IoC容器: 把某些业务对象的的控制权交给一个平台或者框架来同一管理,这个同一管理的平台可以称为I ...

  6. ajax跨域通过 Cors跨域资源共享 进行GetPost请求

    using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Ne ...

  7. merge 本地 master 分支代码提示 “Already up-to-date”

    在使用 git 的过程中由于误操作,导致从本地 master 分支 merge 代码到当前分支失败,虽然当前分支和 master 分支代码不同步,但是仍然提示 Already up-to-date. ...

  8. python 数据分析--词云图,图形可视化美国竞选辩论

    这篇博客从用python实现分析数据的一个完整过程.以下着重几个python的moudle的运用"pandas",""wordcloud"," ...

  9. 在strust2 框架下,前端APP传过来的中文数据乱码问题

    public String addMessage() throws UnsupportedEncodingException{ Patient patient=new Patient(); patie ...

  10. Integer.toBinaryString()的源代码解析

    private static String toUnsignedString(int i, int shift) { char[] buf = new char[32];//i是要整形,这里得把它化成 ...