java "回调【 Callback 】" 的理解和使用<借鉴>
2013-09-08 09:57
681 查看
对callback,暂时的理解是:A对象调用B接口的b方法,b方法又反过来调用A对象中的c方法。
A调用B接口时把自身给B接口,至于怎么处理,由B的实现类去做,不关A的事。
写了个例子,BadBoy,这类坏孩子喜欢打人,有个方法叫hit,hit只能对实现了Hitable的对象执行。
这时候,BadBoy已经做完了自己的事,也就是已经打完人了,然后挨打的人肯定知道是谁打了自己,
至于挨打的人是什么反应,BadBoy是无法控制的。挨打的人有可能哭有可能跑有可能报警。
第二种理解:
【1】必须有一个接口,声明实现子类必须实现的方法,比如:
public interface Icalc{
public Object doCalc(int a,int b);
}
【2】中间使用类在自己方法中只针对以上接口进行编程,在自己的方法中以 接口为参数,在方法体中调用接口的方法来完成自己额业务逻辑,具体的逻辑实现不用考虑。
具体实现被推给调用这个使用类的用户完成!
【3】最外层是真正业务逻辑代码的提供者,它去调用【2】步骤中定义的方法时,因为该方法有一个接口参数的变量,
因此它必须在这时实现这个接口,供【2】步骤中相应方法来调用。
本来是调用【2】步骤中的方法,到真正调用时,反过来【2】步骤的方法还要调用【3】步骤中对接口的实现,来完成业务逻辑,
这正应了这个概念的名字 "回调(callback)" !
第三种理解:
总听见Callback如何如何,姑且不评判它的好坏,但是的确提供了一种code的新方式。
Callback我理解是调用方 调用 被调用方函数执行过程中,
被调用方 选择执行 调用方(至少是调用方初始化出来的)的某些函数来通知 调用方或者按照调用方的意愿做某些改变。
Spring中的JdbcTemplate的query方法和execute方法就使用了大量的Callback。
初始场景:A——调用者;B——被调用者。
最简单的方式是 A的方法调用B的过程中,A将自身this作为一个参数传递给到b的执行函数中。
这样,在执行b的方法时,就能够反过来操纵a的方法了。但是这种方式A和B循环依赖。不是一种很好的选择。
一种更为优雅的方式是:申明一个ICallBack接口,作为执行B方法的参数。
B在执行自己代码的过程中,执行callback对象对应的方法。
那么,在A开始调用时,实现ICallBack接口(可以大量使用A自身的资源:a知道该怎么办),并且在调用B方法时将callback对象传入。
这样,A依赖于Callback,B也依赖于CallBack。因此有效的解耦。
应用场景:A有多个方法要调用B的某个方法,B的这个方法很多逻辑相同,但是,小部分逻辑根据A的调用方法不同而不同。
因此,使用Callback方法:1)创建ICallback接口;
2)在A的调用地方实现callback类;
3)在这个类中写不同的业务逻辑;
4)B的方法写固定的业务逻辑并且接受ICallBack对象执行。
可能出现的问题:如果A的若干个执行方法中,要求响应对象不一致,尝试泛型是否可以解决!
实例理解:
[java] view
plaincopyprint?
package com.itm.CallBack;
interface Hitable {
/*
挨打的人的接口,他们有一个共同的方法,
就是beHit(BadBoy boy),既然挨打了,肯定知道是谁打的自己,所以打人者BadBoy被作为参数传进来。
*
*/
public void beHit(BadBoy boy);
public String getName();
public void setName(String name);
}
[java] view
plaincopyprint?
package com.itm.CallBack;
class BadBoy {
String name;
public BadBoy(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//打人
public void hit(Hitable hitable) {
System.out.println("----------------BEGIN----------------");
System.out.println("badboy " + this.getName() + "打了"
+ hitable.getName() + "一拳");
hitable.beHit(this);
System.out.println("-----------------END----------------");
}
}
[java] view
plaincopyprint?
package com.itm.CallBack;
/*Child:这个类实现了Hitable,小孩挨打了,反应是哭。。*/
class Child implements Hitable {
String name;
public Child(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void beHit(BadBoy boy) {
System.out.println("child " + this.getName() + "被" + boy.getName()
+ "打哭了");
}
}
[java] view
plaincopyprint?
package com.itm.CallBack;
/*
*
* BigMan也实现了Hitable接口,这类人比较猛,挨打后的反应,是把打人者杀了。。
*
*
* */
class BigMan implements Hitable {
String name;
public BigMan(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void beHit(BadBoy boy) {
System.out.println("bigman " + this.getName() + "把" + boy.getName()
+ "杀死了");
}
}
测试类:
[java] view
plaincopyprint?
package com.itm.CallBack;
public class CallBackTest {
public static void main(String[] args) {
BadBoy badboy = new BadBoy("Tom");
Hitable child = new Child("Cat");
Hitable bigman = new BigMan("Boris");
badboy.hit(child);
badboy.hit(bigman);
}
}
JAVA实现回调【摘抄,很经典】
熟悉MS-Windows和X Windows事件驱动设计模式的开发人员,通常是把一个方法的指针传递给事件源,当某一事件发生时来调用这个方法(也称为“回调”)。
Java的面向对象的模型目前不支持方法指针,似乎不能使用这种方便的机制。
Java支持interface,通过interface可以实现相同的回调。其诀窍就在于定义一个简单的interface,申明一个被希望回调的方法。
例如,假定当某一事件发生时会得到通知,我们可以定义一个interface:
[java] view
plaincopyprint?
public interface InterestingEvent {
// 这只是一个普通的方法,可以接收参数、也可以返回值
public void interestingEvent();
}
这样我们就有了任何一个实现了这个接口类对象的手柄grip。
当一事件发生时,需要通知实现InterestingEvent 接口的对象,并调用interestingEvent() 方法。
[java] view
plaincopyprint?
class EventNotifier {
private InterestingEvent ie;
private boolean somethingHappened;
public EventNotifier(InterestingEvent event) {
ie = event;
somethingHappened = false;
}
public void doWork() {
if (somethingHappened) {
// 事件发生时,通过调用接口的这个方法来通知
ie.interestingEvent();
}
}
}
在这个例子中,用somethingHappened 来标志事件是否发生。
希望接收事件通知的类必须要实现InterestingEvent 接口,而且要把自己的引用传递给事件的通知者。
[java] view
plaincopyprint?
public class CallMe implements InterestingEvent {
private EventNotifier en;
public CallMe() {
// 新建一个事件通知者对象,并把自己传递给它
en = new EventNotifier(this);
}
// 实现事件发生时,实际处理事件的方法
public void interestingEvent() {
// 这个事件发生了,进行处理
}
}
以上是通过一个非常简单的例子来说明Java中的回调的实现。
以下为经典实例演示:
当然,也可以在事件管理或事件通知者类中,通过注册的方式来注册多个对此事件感兴趣的对象。
1. 定义一个接口InterestingEvent ,回调方法nterestingEvent(String event) 简单接收一个String 参数。
[java] view
plaincopyprint?
interface InterestingEvent {
public void interestingEvent(String event);
}
2. 实现InterestingEvent接口,事件处理类
[java] view
plaincopyprint?
class CallMe implements InterestingEvent {
private String name;
public CallMe(String name){
this.name = name;
}
public void interestingEvent(String event) {
System.out.println(name + ":[" +event + "] happened");
}
}
3. 事件管理者,或事件通知者
[java] view
plaincopyprint?
package com.itm.CallBack;
import java.util.ArrayList;
import java.util.List;
class EventNotifier {
private List<CallMe> callMes = new ArrayList<CallMe>();
public void regist(CallMe callMe){
callMes.add(callMe);
}
public void doWork(){
for(CallMe callMe: callMes) {
// 事件触发了****
callMe.interestingEvent("sample event");
}
}
}
4. 测试
[java] view
plaincopyprint?
public class CallMeTest {
public static void main(String[] args) {
EventNotifier ren = new EventNotifier();
CallMe a = new CallMe("CallMe A");
CallMe b = new CallMe("CallMe B");
// regiest
ren.regist(a);
ren.regist(b);
// test
ren.doWork();
}
}
A调用B接口时把自身给B接口,至于怎么处理,由B的实现类去做,不关A的事。
写了个例子,BadBoy,这类坏孩子喜欢打人,有个方法叫hit,hit只能对实现了Hitable的对象执行。
这时候,BadBoy已经做完了自己的事,也就是已经打完人了,然后挨打的人肯定知道是谁打了自己,
至于挨打的人是什么反应,BadBoy是无法控制的。挨打的人有可能哭有可能跑有可能报警。
第二种理解:
【1】必须有一个接口,声明实现子类必须实现的方法,比如:
public interface Icalc{
public Object doCalc(int a,int b);
}
【2】中间使用类在自己方法中只针对以上接口进行编程,在自己的方法中以 接口为参数,在方法体中调用接口的方法来完成自己额业务逻辑,具体的逻辑实现不用考虑。
具体实现被推给调用这个使用类的用户完成!
【3】最外层是真正业务逻辑代码的提供者,它去调用【2】步骤中定义的方法时,因为该方法有一个接口参数的变量,
因此它必须在这时实现这个接口,供【2】步骤中相应方法来调用。
本来是调用【2】步骤中的方法,到真正调用时,反过来【2】步骤的方法还要调用【3】步骤中对接口的实现,来完成业务逻辑,
这正应了这个概念的名字 "回调(callback)" !
第三种理解:
总听见Callback如何如何,姑且不评判它的好坏,但是的确提供了一种code的新方式。
Callback我理解是调用方 调用 被调用方函数执行过程中,
被调用方 选择执行 调用方(至少是调用方初始化出来的)的某些函数来通知 调用方或者按照调用方的意愿做某些改变。
Spring中的JdbcTemplate的query方法和execute方法就使用了大量的Callback。
初始场景:A——调用者;B——被调用者。
最简单的方式是 A的方法调用B的过程中,A将自身this作为一个参数传递给到b的执行函数中。
这样,在执行b的方法时,就能够反过来操纵a的方法了。但是这种方式A和B循环依赖。不是一种很好的选择。
一种更为优雅的方式是:申明一个ICallBack接口,作为执行B方法的参数。
B在执行自己代码的过程中,执行callback对象对应的方法。
那么,在A开始调用时,实现ICallBack接口(可以大量使用A自身的资源:a知道该怎么办),并且在调用B方法时将callback对象传入。
这样,A依赖于Callback,B也依赖于CallBack。因此有效的解耦。
应用场景:A有多个方法要调用B的某个方法,B的这个方法很多逻辑相同,但是,小部分逻辑根据A的调用方法不同而不同。
因此,使用Callback方法:1)创建ICallback接口;
2)在A的调用地方实现callback类;
3)在这个类中写不同的业务逻辑;
4)B的方法写固定的业务逻辑并且接受ICallBack对象执行。
可能出现的问题:如果A的若干个执行方法中,要求响应对象不一致,尝试泛型是否可以解决!
实例理解:
[java] view
plaincopyprint?
package com.itm.CallBack;
interface Hitable {
/*
挨打的人的接口,他们有一个共同的方法,
就是beHit(BadBoy boy),既然挨打了,肯定知道是谁打的自己,所以打人者BadBoy被作为参数传进来。
*
*/
public void beHit(BadBoy boy);
public String getName();
public void setName(String name);
}
[java] view
plaincopyprint?
package com.itm.CallBack;
class BadBoy {
String name;
public BadBoy(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//打人
public void hit(Hitable hitable) {
System.out.println("----------------BEGIN----------------");
System.out.println("badboy " + this.getName() + "打了"
+ hitable.getName() + "一拳");
hitable.beHit(this);
System.out.println("-----------------END----------------");
}
}
[java] view
plaincopyprint?
package com.itm.CallBack;
/*Child:这个类实现了Hitable,小孩挨打了,反应是哭。。*/
class Child implements Hitable {
String name;
public Child(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void beHit(BadBoy boy) {
System.out.println("child " + this.getName() + "被" + boy.getName()
+ "打哭了");
}
}
[java] view
plaincopyprint?
package com.itm.CallBack;
/*
*
* BigMan也实现了Hitable接口,这类人比较猛,挨打后的反应,是把打人者杀了。。
*
*
* */
class BigMan implements Hitable {
String name;
public BigMan(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void beHit(BadBoy boy) {
System.out.println("bigman " + this.getName() + "把" + boy.getName()
+ "杀死了");
}
}
测试类:
[java] view
plaincopyprint?
package com.itm.CallBack;
public class CallBackTest {
public static void main(String[] args) {
BadBoy badboy = new BadBoy("Tom");
Hitable child = new Child("Cat");
Hitable bigman = new BigMan("Boris");
badboy.hit(child);
badboy.hit(bigman);
}
}
JAVA实现回调【摘抄,很经典】
熟悉MS-Windows和X Windows事件驱动设计模式的开发人员,通常是把一个方法的指针传递给事件源,当某一事件发生时来调用这个方法(也称为“回调”)。
Java的面向对象的模型目前不支持方法指针,似乎不能使用这种方便的机制。
Java支持interface,通过interface可以实现相同的回调。其诀窍就在于定义一个简单的interface,申明一个被希望回调的方法。
例如,假定当某一事件发生时会得到通知,我们可以定义一个interface:
[java] view
plaincopyprint?
public interface InterestingEvent {
// 这只是一个普通的方法,可以接收参数、也可以返回值
public void interestingEvent();
}
这样我们就有了任何一个实现了这个接口类对象的手柄grip。
当一事件发生时,需要通知实现InterestingEvent 接口的对象,并调用interestingEvent() 方法。
[java] view
plaincopyprint?
class EventNotifier {
private InterestingEvent ie;
private boolean somethingHappened;
public EventNotifier(InterestingEvent event) {
ie = event;
somethingHappened = false;
}
public void doWork() {
if (somethingHappened) {
// 事件发生时,通过调用接口的这个方法来通知
ie.interestingEvent();
}
}
}
在这个例子中,用somethingHappened 来标志事件是否发生。
希望接收事件通知的类必须要实现InterestingEvent 接口,而且要把自己的引用传递给事件的通知者。
[java] view
plaincopyprint?
public class CallMe implements InterestingEvent {
private EventNotifier en;
public CallMe() {
// 新建一个事件通知者对象,并把自己传递给它
en = new EventNotifier(this);
}
// 实现事件发生时,实际处理事件的方法
public void interestingEvent() {
// 这个事件发生了,进行处理
}
}
以上是通过一个非常简单的例子来说明Java中的回调的实现。
以下为经典实例演示:
当然,也可以在事件管理或事件通知者类中,通过注册的方式来注册多个对此事件感兴趣的对象。
1. 定义一个接口InterestingEvent ,回调方法nterestingEvent(String event) 简单接收一个String 参数。
[java] view
plaincopyprint?
interface InterestingEvent {
public void interestingEvent(String event);
}
2. 实现InterestingEvent接口,事件处理类
[java] view
plaincopyprint?
class CallMe implements InterestingEvent {
private String name;
public CallMe(String name){
this.name = name;
}
public void interestingEvent(String event) {
System.out.println(name + ":[" +event + "] happened");
}
}
3. 事件管理者,或事件通知者
[java] view
plaincopyprint?
package com.itm.CallBack;
import java.util.ArrayList;
import java.util.List;
class EventNotifier {
private List<CallMe> callMes = new ArrayList<CallMe>();
public void regist(CallMe callMe){
callMes.add(callMe);
}
public void doWork(){
for(CallMe callMe: callMes) {
// 事件触发了****
callMe.interestingEvent("sample event");
}
}
}
4. 测试
[java] view
plaincopyprint?
public class CallMeTest {
public static void main(String[] args) {
EventNotifier ren = new EventNotifier();
CallMe a = new CallMe("CallMe A");
CallMe b = new CallMe("CallMe B");
// regiest
ren.regist(a);
ren.regist(b);
// test
ren.doWork();
}
}
相关文章推荐
- java "回调【 Callback 】" 的理解和使用<借鉴>
- <jsp:invoke fragment=""/>的理解和使用
- <Java>一个类bytebuffer使用
- 使用<bean:define >取到bean:write的值,并赋值给java变量
- 回发或回调参数无效。在配置中使用 <pages enableEventValidation="true"/> 或在页面中使用 <%@ Page EnableEventValidation="true"
- <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>标签再使用时报错
- ASP.NET中使用<script runat="server">
- 使用<base target="_self" /> IE6 cann't open the Internet site 已终止操作
- <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>意义
- <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>标签再使用时报错
- <div style="display:none">中更改的内容使用js无法获取
- 使用<input type="file">实现文件上传
- 使用<input type="text" value=<%=str%>>出现取值不全的问题
- spring3 jsp页面使用<form:form modelAttribute="xxxx" action="xxxx">报错,附连接数据库的spring MVC annotation 案例
- System.ArgumentException: 回发或回调参数无效。在配置中使用 < pages enableEventValidation="true"/>
- 回发或回调参数无效。在配置中使用 <pages enableEventValidation="true"/>
- java 位移运算符 ">>" "<<" ">>>"
- 使用<a href="../answer/StuAnswer.jsp?Sid=<%=Sid %>&Eid=1">shuxue</a> 注意
- <转>学习java反编译工具的使用
- System.ArgumentException: 回发或回调参数无效。在配置中使用 < pages enableEventValidation="true"/>