java 设计模式之 观察者模式(Observer)

Python015

java 设计模式之 观察者模式(Observer),第1张

//Subject java

package youngmaster model Observer

/**

* @author youngmaster

* @E mail:young * @version myEclipse

* @create time 上午 : :

*/

/**

* 察者模式属于行为型模式 其意图是定义对象间的一种一对多的依赖关系

* 当一个对象的状态发生改变时 所有依赖于它的对象都得到通知并被自动更新

* 在制作系统的过程中 将一个系统分割成一系列相互协作的类有一个常见的副作用

* 需要维护相关对象间的一致性 我们不希望为了维持一致性而使各类紧密耦合

* 因为这样降低了他们的可充用性 这一个模式的关键对象是目标(Subject)和观察者(Observer)

* 一个目标可以有任意数目的依赖它的观察者 一旦目标的状态发生改变 所有的观察者都得到通知

* 作为对这个通知的响应 每个观察者都将查询目标以使其状态与目标的状态同步 这种交互也称为发布 订阅模式

* 目标是通知的发布者 他发出通知时并不需要知道谁是他的观察者 可以有任意数据的观察者订阅并接收通知

*/

/**

* subject

*目标接口

*/

public interface Subject {

public void addObserver(Observer o)

public void deletObserver(Observer o)

public void notice()

}

//Observer java

package youngmaster model Observer

/**

* @author youngmaster

* @E mail:young * @version myEclipse

* @create time 上午 : :

*/

/**

*观察者接口

*/

public interface Observer {

public void update()

}

//Teacher java

package youngmaster model Observer

import java util Vector

/**

* @author youngmaster

* @E mail:young * @version myEclipse

* @create time 上午 : :

*/

/**

*目标接口实现

*/

public class Teacher implements Subject {

private String phone

@SuppressWarnings( unchecked )

private Vector students

@SuppressWarnings( unchecked )

public Teacher() {

phone =

students = new Vector()

}

@SuppressWarnings( unchecked )

@Override

public void addObserver(Observer o) {

students add(o)

}

@Override

public void deletObserver(Observer o) {

students remove(o)

}

@Override

public void notice() {

for (int i = i <students size()i++) { ((Observer) students get(i)) update()

}

}

public void setPhone(String phone) {

this phone = phone

notice()

}

public String getPhone() {

return phone

}

}

//Student java

package youngmaster model Observer

/**

* @author youngmaster

* @E mail:young * @version myEclipse

* @create time 上午 : :

*/

/**

*观察者接口实现

*/

public class Student implements Observer {

private String name

private String phone

private Teacher teacher

public Student(String name Teacher teacher) { this name = namethis teacher = teacher

}

public void show() {

System out println( Name: + name + \nTeacher s phone: + phone)

}

@Override

public void update() {

phone = teacher getPhone()

}

}

//Client java

package youngmaster model Observer

import java util Vector

/**

* @author youngmaster

* @E mail:young * @version myEclipse

* @create time 上午 : :

*/

/**

*测试类

*/

public class Client {

/**

* @param args

*/

@SuppressWarnings( unchecked )

public static void main(String[] args) {

Vector students = new Vector()

Teacher teacher = new Teacher()

for (int i = i <i++) {

Student student = new Student( student + i teacher)students add(student)teacher addObserver(student)

}

teacher setPhone( )

for (int i = i <i++)

((Student) students get(i)) show()

System out println( \n============================\n )

teacher setPhone( )

for (int i = i <i++)

((Student) students get(i)) show()

}

lishixinzhi/Article/program/Java/gj/201311/27566

MyEventTest java:

package wintys event

import javax swing event EventListenerList

import java util Date

import java text DateFormat

import java text SimpleDateFormat

/**

* Java的事件机制/自定义事件

运行结果:

do something interesting in source here

listener detects [event]:wintys event MyEvent[source=wintys event MySource@

] [occur at]: : :

listener detects [event]:wintys event MyEvent[source=wintys event MySource@

] [occur at]: : :

* @version

* @author 天堂露珠 ()

* @see

*/

class MyEventTest{

public static void main(String[] args){

MySource source = new MySource()

MyListener myListener = new MyListener(){

public void doMyAction(MyEvent e){

System out println( listener detects + e)

}

}

source addMyListener(myListener)

source addMyListener(myListener)

source addMyListener(myListener)

source removeMyListener(myListener)

source doSomething()

}

}

/**

* 自定义的事件

* @version

* @author 天堂露珠()

* @see

*/

class MyEvent extends java util EventObject{

private Date date//记录事件发生的时间

public MyEvent(Object source Date date){

super(source)

this date = date

}

public String toString(){

DateFormat df = new SimpleDateFormat( yyyy MM dd HH:mm:ss )

String dt = df format(date)

return [event]: + super toString() + [occur at]: + dt

}

}

/**

* 自定义事件监听器接口

* @version

* @author 天堂露珠()

* @see

*/

interface MyListener extends java util EventListener{

void doMyAction(MyEvent e)

}

/**

* 自定义事件源

* @version

* @author 天堂露珠()

* @see

*/

class MySource{

/**

* 保存注册的监听器列表

* 子类可以使用它保存自己的事件监听器(非MyListener监听器)列表

*/

protected EventListenerList listenerList = new EventListenerList()

private MyEvent myEvent = null//fireDoMyAction()使用此变量

/**

* 没有做任何事

*/

public MySource(){

}

/**

* 添加一个MyListener监听器

*/

public void addMyListener(MyListener listener){

listenerList add(MyListener class listener)

}

/**

* 移除一个已注册的MyListener监听器

* 如果监听器列表中已有相同的监听器listener listener

* 并且listener ==listener

* 那么只移除最近注册的一个监听器

*/

public void removeMyListener(MyListener listener){

listenerList remove(MyListener class listener)

}

/**

* @return 在此对象上监听的所有MyListener类型的监听器

*/

public MyListener[] getMyListeners(){

return (MyListener[])listenerList getListeners(MyListener class)

}

//Winty:Copy directly from javax swing event EventListenerList

/*Notify all listeners that have registered interest for

notification on this event type The event instance

is lazily created using the parameters passed into

the fire method

*/

protected void fireDoMyAction() {

// getListenerList() Guaranteed to return a non null array

Object[] listeners = listenerList getListenerList()

// Process the listeners last to first notifying

// those that are interested in this event

for (int i = listeners length i>= i = ) {

if (listeners[i]==MyListener class) {

// Lazily create the event:

if (myEvent == null)

myEvent = new MyEvent(this new Date())

((MyListener)listeners[i+ ]) doMyAction(myEvent)

}

}

}

/**

* 做一些事件源应该做的有意义的事 然后通知监听器

* 这里只是一个示例方法

* 例如:MySource如果是一个按钮 则doSomething()就可以命名为click()

* 当用户点击按钮时调用click()方法

*/

public void doSomething() {

System out println( do something interesting here )

fireDoMyAction()//通知监听器

}

}

lishixinzhi/Article/program/Java/hx/201311/26237

转自( https://my.oschina.net/u/923324/blog/792857 )

背景

关于设计模式,之前笔者写过工厂模式,最近在使用gava ListenableFuture时发现事件监听模型特别有意思,于是就把事件监听、观察者之间比较了一番,发现这是一个非常重要的设计模式,在很多框架里扮演关键的作用。

回调函数

为什么首先会讲回调函数呢?因为这个是理解监听器、观察者模式的关键。

什么是回调函数

所谓的回调,用于回调的函数。 回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数。 有这么一句通俗的定义:就是程序员A写了一段程序(程序a),其中预留有回调函数接口,并封装好了该程序。程序员B要让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法。

举个例子:

这里有两个实体:回调抽象接口、回调者(即程序a)

回调接口(ICallBack )

public interface ICallBack {

public void callBack()

}

回调者(用于调用回调函数的类)

public class Caller {

}

回调测试:

public static void main(String[] args) {

Caller call = new Caller()

call.call(new ICallBack(){

控制台输出:

start...

终于回调成功了!

end...

还有一种写法

或实现这个ICallBack接口类

class CallBackC implements ICallBack{

@Override

public void callBack() {

System.out.println("终于回调成功了!")

}

}

有没有发现这个模型和执行一个线程,Thread很像。 没错,Thread就是回调者,Runnable就是一个回调接口。

new Thread(new Runnable(){

@Override

public void run() {

System.out.println("回调一个新线程!")

}}).start()

Callable也是一个回调接口,原来一直在用。 接下来我们开始讲事件监听器

事件监听模式

什么是事件监听器

监听器将监听自己感兴趣的事件一旦该事件被触发或改变,立即得到通知,做出响应。例如:android程序中的Button事件。

java的事件监听机制可概括为3点:

java的事件监听机制涉及到 事件源,事件监听器,事件对象 三个组件,监听器一般是接口,用来约定调用方式

当事件源对象上发生操作时,它将会调用事件监听器的一个方法,并在调用该方法时传递事件对象过去

事件监听器实现类,通常是由开发人员编写,开发人员通过事件对象拿到事件源,从而对事件源上的操作进行处理

举个例子

这里我为了方便,直接使用jdk,EventListener 监听器,感兴趣的可以去研究下源码,非常简单。

监听器接口

public interface EventListener extends java.util.EventListener {

//事件处理

public void handleEvent(EventObject event)

}

事件对象

public class EventObject extends java.util.EventObject{

private static final long serialVersionUID = 1L

public EventObject(Object source){

super(source)

}

public void doEvent(){

System.out.println("通知一个事件源 source :"+ this.getSource())

}

}

事件源

事件源是事件对象的入口,包含监听器的注册、撤销、通知

public class EventSource {

//监听器列表,监听器的注册则加入此列表

private Vector<EventListener>ListenerList = new Vector<EventListener>()

//注册监听器

public void addListener(EventListener eventListener){

ListenerList.add(eventListener)

}

//撤销注册

public void removeListener(EventListener eventListener){

ListenerList.remove(eventListener)

}

//接受外部事件

public void notifyListenerEvents(EventObject event){

for(EventListener eventListener:ListenerList){

eventListener.handleEvent(event)

}

}

}

测试执行

public static void main(String[] args) {

EventSource eventSource = new EventSource()

}

控制台显示:

通知一个事件源 source :openWindows

通知一个事件源 source :openWindows

doOpen something...

到这里你应该非常清楚的了解,什么是事件监听器模式了吧。 那么哪里是回调接口,哪里是回调者,对!EventListener是一个回调接口类,handleEvent是一个回调函数接口,通过回调模型,EventSource 事件源便可回调具体监听器动作。

有了了解后,这里还可以做一些变动。 对特定的事件提供特定的关注方法和事件触发

public class EventSource {

...

public void onCloseWindows(EventListener eventListener){

System.out.println("关注关闭窗口事件")

ListenerList.add(eventListener)

}

}

public static void main(String[] args) {

EventSource windows = new EventSource()

/**

* 另一种实现方式

*/

//关注关闭事件,实现回调接口

windows.onCloseWindows(new EventListener(){

}

这种就类似于,我们的窗口程序,Button监听器了。我们还可以为单击、双击事件定制监听器。

观察者模式

什么是观察者模式

观察者模式其实原理和监听器是一样的,使用的关键在搞清楚什么是观察者、什么是被观察者。

观察者(Observer)相当于事件监器。有个微博模型比较好理解,A用户关注B用户,则A是B的观察者,B是一个被观察者,一旦B发表任何言论,A便可以获得。

被观察者(Observable)相当于事件源和事件,执行事件源通知逻辑时,将会回调observer的回调方法update。

举个例子

为了方便,同样我直接使用jdk自带的Observer。

一个观察者

public class WatcherDemo implements Observer {

@Override

public void update(Observable o, Object arg) {

if(arg.toString().equals("openWindows")){

System.out.println("已经打开窗口")

}

}

}

被观察者

Observable 是jdk自带的被观察者,具体可以自行看源码和之前的监听器事件源类似。

主要方法有

addObserver() 添加观察者,与监听器模式类似

notifyObservers() 通知所有观察者

类Watched.java的实现描述:被观察者,相当于事件监听的事件源和事件对象。又理解为订阅的对象 主要职责:注册/撤销观察者(监听器),接收主题对象(事件对象)传递给观察者(监听器),具体由感兴趣的观察者(监听器)执行

/**

}

测试执行

public static void main(String[] args) {

Watched watched = new Watched()

WatcherDemo watcherDemo = new WatcherDemo()

watched.addObserver(watcherDemo)

watched.addObserver(new Observer(){

@Override

public void update(Observable o, Object arg) {

if(arg.toString().equals("closeWindows")){

System.out.println("已经关闭窗口")

}

}

})

//触发打开窗口事件,通知观察者

watched.notifyObservers("openWindows")

//触发关闭窗口事件,通知观察者

watched.notifyObservers("closeWindows")

控制台输出:

已经打开窗口

已经关闭窗口

总结

从整个实现和调用过程来看,观察者和监听器模式基本一样。

有兴趣的你可以基于这个模型,实现一个简单微博加关注和取消的功能。 说到底,就是事件驱动模型,将调用者和被调用者通过一个链表、回调函数来解耦掉,相互独立。

“你别来找我,有了我会找你”。

整个设计模式的初衷也就是要做到低耦合,低依赖。

再延伸下,消息中间件是什么一个模型? 将生产者+服务中心(事件源)和消费者(监听器)通过消息队列解耦掉. 消息这相当于具体的事件对象,只是存储在一个队列里(有消峰填谷的作用),服务中心回调消费者接口通过拉或取的模型响应。 想必基于这个模型,实现一个简单的消息中间件也是可以的。

还比如gava ListenableFuture,采用监听器模式就解决了future.get()一直阻塞等待返回结果的问题。

有兴趣的同学,可以再思考下观察者和责任链之间的关系, 我是这样看的。

同样会存在一个链表,被观察者会通知所有观察者,观察者自行处理,观察者之间互不影响。 而责任链,讲究的是击鼓传花,也就是每一个节点只需记录继任节点,由当前节点决定是否往下传。 常用于工作流,过滤器web filter。