首页编程java编程java 回调和监听器什么关系 java设计模式-回调、事件监听器、观察者模式

java 回调和监听器什么关系 java设计模式-回调、事件监听器、观察者模式

编程之家2023-10-1398次浏览

大家好,今天小编来为大家解答以下的问题,关于java 回调和监听器什么关系,java设计模式-回调、事件监听器、观察者模式这个很多人还不知道,现在让我们一起来看看吧!

java 回调和监听器什么关系 java设计模式-回调、事件监听器、观察者模式

java设计模式-回调、事件监听器、观察者模式

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

背景

java 回调和监听器什么关系 java设计模式-回调、事件监听器、观察者模式

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

回调函数

java 回调和监听器什么关系 java设计模式-回调、事件监听器、观察者模式

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

什么是回调函数

所谓的回调,用于回调的函数。回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数。有这么一句通俗的定义:就是程序员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。

java web 过滤器跟拦截器的区别和使用

区别如下:

1、拦截器是基于java的反射机制的,而过滤器是基于函数回调。

2、拦截器不依赖与servlet容器,过滤器依赖与servlet容器。

3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。

4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。

5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

使用如下:

在Servlet作为过滤器使用时,它可以对客户的请求进行处理。处理完成后,它会交给下一个过滤器处理,这样,客户的请求在过滤链里逐个处理,直到请求发送到目标为止。例如,某网站里有提交“修改的注册信息”的网页,当用户填写完修改信息并提交后,服务器在进行处理时需要做两项工作:判断客户端的会话是否有效;对提交的数据进行统一编码。

这两项工作可以在由两个过滤器组成的过滤链里进行处理。当过滤器处理成功后,把提交的数据发送到最终目标;如果过滤器处理不成功,将把视图派发到指定的错误页面。

扩展资料:

拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。

在Webwork的中文文档的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。

过滤器是一个程序,它先于与之相关的servlet或JSP页面运行在服务器上。过滤器可附加到一个或多个servlet或JSP页面上,并且可以检查进入这些资源的请求信息。

参考资料:百度百科-java

给讲讲java接口的概念!

希望你仔细阅读。对初学者来说,接口不是很好理解。我教过的学生也都提出过这个问题。

我们来看一个类

class A{

private int a;

public int getA(){

return a;

}

}

这个类的属性是私有的,外界不能访问,而外界可以通过公有方法来访问这个类。我们说一个类的公有方法就是这个类的对外接口。通常

一个类的属性都是私有的,方法大多是公有的。外界只能过个这些公有方法来访问类。这也是Java封装性的体现。如果一个类没有公有属性,

也没有公有方法,这个类就是无法使用的类了。所以我们需要为一个类提供对外接口。

一个类中的方法,不只是说明了它要“做什么”,而且方法的内容也说明了“怎么做”。打个不太恰当的例子,一个杀人方法。从名字上

看,你知道了“做什么”,但没有办法看到“怎么做”。而方法的内容说明了“怎么做”。

class killer{

private String name;

private int age;

private String phone;

private String addr;

......

public void kill(Person p){

Qiang qiang= new Qiang("ak47");

qiang.fire(p);

}

}

这个类的kill方法内容说明了杀人的过程。如果你不想用这种方式杀人。因为你很BT,你想用毒药杀人。那么这个类的内容就需要改。但

是,还有很多其它的“客户”,需要用不同的方式杀人。怎么办呢?一个很好的办法就是,我们只定义“做什么”,而不定义“怎么做”。

interface Killer{

public void kill(Person p);

}

接口说明了“做什么”,而实现这个接口的类,也就是实现类需要说明“怎么做”。

class Killer1 implements Killer{

public void kill(Person p){

Qiang qiang= new Qiang("ak47");

qiang.fire(p);

}

}

class Killer2 implements Killer{

public void kill(Person p){

Bane bane= new Bane();

p.eat(bane);

}

}

public class Test{

public static void main(String[] args){

Killer jingKe= new Killer1();

Person yingZheng= new Person();

jingKe.kill(yingZheng);

}

}

接口可以把“做什么”和“怎么做”分离开来。这给Java带来了很多好处。虽然代码量增加了,可我们的程序的可维护性加强了。我们的程序是可以拆分的。就象电脑一样,可以拆分成很多组件。我一直在想,如果我的MP3耳机可以拆分就好了,那样在耳机只坏掉一个的时候就不用重新买一个了。

不过上面的例子看不到什么太大的好处。你可能会说,如果你

的目的是为了不修改代码,那么,如果我想使用Killer2来完成任务,还是需要修改main方法为:Killer jingKe= new Killer2();。没有错,

不过你可以通过一个工厂来完成上面的任务。也就是说,不通过new语句来获得Killer对象,而是通过工厂来获得Killer对象。

public class KillerFactory{

public static killer getKiller(){

return new Killer1();

}

public static Killer getKiller(String path) throws Exception{

Properties prop= new Properties();

prop.load(new FileInputStream(path));

String className= prop.getProperty("killer");

Class clazz= Class.forName(className);

return(Killer)clazz.newInstance();

}

}

代码确实增加了很多,可是这对后期的系统维修和系统升级带来了很多好处。

水龙头与出水管的关系,我们需要把水龙头安装到出水管上。如果有一天我们需要更换水龙头时,只需要把老的水龙头拆卸下来,把新的

水龙头安装到出水管上既可。如果水龙头与出水管是一体的,就是无法拆卸的怎么办呢?或是说出水管只能安装水龙头,而不能安装淋浴器,

这就使我们生活很不方便。我们可以理解为出水管的连接方法,连接的对象是“出水设备”,而这个“出水设备”是一个接口。而水龙头与淋

浴器都是这个接口的实现类。但是接口在哪里呢?它长什么样子?我们没看到。它是一个标准,连接处的内径与外径。螺丝抠的密度等。这就

和你的电脑上为什么可以连接USB设备一样。如果电脑和某一个USB设备电焊到一起,那么其它的USB设备就无法使用了。电脑使用的是实现了

USB接口的电子设备,而我们的U盘、MP3、移动硬盘及鼠标都是USB接口的实现类。

用Java写出来的程序也和我们现实生活中的设备一样。如电脑,我们希望电脑的所有部件都可以更换,如果主板上的内存插槽与内存条不

附。我们说,内存条没有实现某某接口。Java是完全面向对象的,而面向对象是我们最为熟悉的东东。面向对象并不简单,而是我们太熟悉它

了。所以我们学习Java会很方便。在现实社会中,所有的标准到了Java中都是接口。一盒香烟多少支烟,烟的长度等都是标准。一个光盘的大

小。Java中的JDBC就是一个标准,而各大数据库厂商及第三方厂商实现了这一标准。JDBC只说明了目的,没有说明怎么完成的目的。

面向对象就在我们眼前,不过我们有时不太注意它。希望你在今后学习Java时,多与现实社会联系。这样可以有利与你的理解。

代码量加大了,但对后期的维护与升级提供了方便。软件公司卖给客户的是class文件,而不是java文件。如果你的客户需要更换Killer对

象,只需修改资源文件既可。

下面我们来看一个定时器类。现在什么都是自动化的,如空调、电视、洗衣机等等。都要用到定时器这个类。对了,还有定时炸弹也要用

它。那我们可不可以只写一个定时器类,应用到所有的需要定时器的设备上呢?答案是肯定的,我们需要这个类。

好了,我们来分析一下定时器需要完成什么工作吧。定时器应该有启动、停止方法。定时器启动之后,每过一定时间就执行某个动作。其

中时间间隔为long型,而要执行的动作可能是输出一个字符串,也可能是打印作业。具体要干什么由使用定时器的用户来完成。而定义定时器

时,根本就不知道要干什么。

public class Timmer{

private long time;

private Action action;

public Timmer(){}

public Timmer(long time, Action action){

this.time= time;

this.action= action;

}

public void start(){

state= START;

if(th== null){

th= new Thread(){

public void run(){

while(state== START){

try{

Thread.sleep(time);

action.action();

} catch(Exception e){

}

}

}

};

}

th.start();

}

public void stop(){

state= STOP;

}

public void setTime(long time){

this.time= time;

}

public void setAction(Action action){

this.action= action;

}

public long getTime(){

return(this.time);

}

public Action getAction(){

return(this.action);

}

}

Action是一个接口,它只有一个方法,就是要完成的任务。我们在定时器启动时调用这个接口的方法。而这个Action接口的对象,代表一

个动作,这个动作就是用户要完成的动作。

public interface Action{

public void action();

}

public static void main(String[] args){

Timer t= new Timer(2000, new Action(){

public void action(){

System.out.println("Hello World!");

}

});

t.start();

javax.swing.JOptionPane.showMessageDialog(null,"点击确定按钮停止定时器");

t.stop();

System.exit(0);

}

这是一个典型的回调方法例子。在AWT中,java使用了大量的监听器。这些监听器都是回调方法。在XML解析器SAX中,也使用了回调方法来解析XML文档。

接口要比抽象类还要抽象。抽象类需要子类继承,而Java是单继承,所以抽象类被限制了。而接口不同,一个类可以实现多个接口。好比人类与程序员类之间的关系。可以说程序员是人类的子类,如果程序员是一个接口。用人类的子类来实现它就会更好。这个子类还可以去实现会计接口、音乐家接口等等。

在struts2.0、spring、hibernate等框架中,都大量使用接口。我们关心的是某个接口与另一个接口之间的关系。而不关心某个实现类与另一个接口实现类的关系。在客观世界中,我们交谈时都大量使用接口,只是我们没有注意罢了。如:我公司需要一个程序员(一个实现了程序员接口的对象)。上课时,讲师有一台计算机,用白板笔在白板上写字(计算机是接口,白板及白板笔也是接口)。讲师希望学生能学会所有的知识(讲师及学生都是接口)。

就说这么多了,还有什么不明白可以与我联系。QQ:51038648

我在北京中科院计算所培训中心做兼职java讲师。我的经验是,要想学好Java,一定要多打代码、吃透代码。如果不勤奋,就一定学不好。看来你是刚刚开始学习Java,你后面的路还很长,而且不是很好走。

OK,关于java 回调和监听器什么关系和java设计模式-回调、事件监听器、观察者模式的内容到此结束了,希望对大家有所帮助。

java语言规定标识符由什么组成,java语言标识符规则是什么java中字符是什么类型?java中string是什么类型