java 回调(callback)函数简介.


一, 什么是回调函数(callback)

假如类A有1个方法a(), 但是它不知道什么时候调用这个方法a().

而类B告诉类A, 我知道什么时候调用.    那么类A就把自己交给类B(作为类B的一个成员),   当时机适合时, 类B会调用类A的a()方法.

那么a() 就叫回调(callback)方法.


可能我上面的解释不够好,

记住关键两点就得了:

1. 类A 要成为类B的一个成员,    java中是通过接口(interface)来实现的.

2. a()的执行由类B决定, 但是执行的是类A的方法a()




二, 什么要使用回调方法.

是啊, 为什么不直接使用类A来调用a()呢?

实际上这个也涉及层次的问题.


实际上, 类B可以调用类A的方法a(),   但是有时也可以调用其他比如类c的方法c(), 只要类c实现了接口, 替换成类B的成员.


也就是说, 客户端只需要跟类B打交道, 无需知道实际执行的哪个类的哪个方法.


比如一个间公司有1个快递部门(类B), 所有员工都可以找这个快递部门寄快递,   但是实际上这个部门是用顺丰(类A)来快递的.

但是当顺丰快递有问题时,  类B也可以找另一间快递公司,比如EMS(类C)来实现.


那么公司员工就不必与真正的快递公司打交道, 只需把物件交给类B去处理就ok了. 也就是这个过程是动态的. 甚至也可以找另一件公司来实现(类D), 只需要类D实现快递接口.



三, 基于上面快递的一个具体例子

现在我们就基于上面的例子写一段代码.


3.1 UML图



可以见上面有5中角色

分别是:

员工:  Employee

快递部门: ExDepartment

回调(快递)接口: Callbackable

具体快递公司: SFExpress & EMS


下面是具体代码:


3.2 Callbackable

这个接口只需要定义1个回调方法method()

public interface Callbackable {
	public void method();
}



3.3 ExDepartment

同样地, 快递部门类必须预留1个接口成员.

它可以选择1个实现了Callbackable接口的对象作为自己的成员,

public class ExDepartment {
	private Callbackable exCompany;

	public void setExCompany(Callbackable exCompany) {
		this.exCompany = exCompany;
	}
	
	public ExDepartment(Callbackable exCompany){
		this.setExCompany(exCompany);
	}
	
	public void sendGoods(){
		exCompany.method();
	}
}

这个部门有1个快递方法sendGoods(), 但是实际上是调用这个快递公司成员的回调方法.method();



3.4 SFExpress

具体的快递公司类顺丰, 必须实现Callbackable接口,

并重写里面回调方法.

public class SFExpress implements Callbackable{

	public void SFSendGoods(){
		System.out.println("Sent goods by SF!");
	}
	
	@Override
	public void method() {
		// TODO Auto-generated method stub
		this.SFSendGoods();
	}
	
}


3.5 EMS

同上

public class EMS implements Callbackable {
	public void EMSSendGoods(){
		System.out.println("Sent GOods by EMS");
	}
	
	@Override
	public void method() {
		// TODO Auto-generated method stub
		this.EMSSendGoods();
	}
	
}


3.6 Employee

员工类, 无需知道具体快递公司的存在, 只需要跟快递部门打交道就ok了

public class Employee {
	public void sendGoods(ExDepartment exd){
		exd.sendGoods();
	}
}


3.7 客户端代码和输出:

		ExDepartment exd = new ExDepartment(new SFExpress());
		
		Employee jack = new Employee();
		jack.sendGoods(exd);
		
		exd.setExCompany(new EMS());
		jack.sendGoods(exd);
		
		exd.setExCompany(new Callbackable() {
							@Override
							public void method(){
								System.out.println("Sent goods by Jimmy!");
							}
						});
		
		jack.sendGoods(exd);


输出:

Sent goods by SF!
Sent GOods by EMS
Sent goods by Jimmy!


可以见到, 员工寄了3次快递, 第一次是顺丰, 第一次是EMS, 但是第三次是某个人(可能两个快递公司都放假, 随便找个人来送)


这个模型的好处时,

无论有什么具体快递类的修改, 只需要修改快递类本身.

而增加快递公司类, 只需让那个类实现回调接口, 而员工类和快递部门类都无需修改的.



四, java的控件事件方法也是用回调来实现的.

上面的代码有这么一段:

exd.setExCompany(new Callbackable() {
							@Override
							public void method(){
								System.out.println("Sent goods by Jimmy!");
							}
						});

上面用到了内部类的方法.

是不是觉得有d面善.


这种写法跟java的button事件定义优点类似.

下面是新建1个button的例子:

JButton btnNewButton = new JButton("New button");
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
			}
		});



其中btnNewButton就相当于上面例子的快递部门ExDepartment

而ActionListener实际上就是1个回调接口. (在这里也叫监听器)

而actionPerFormed就是1个回调方法.



没错, java界面(awt/swt)的控件事件就是通过回调来实现的.


你们想想, 一个button,  按下去做什么不是固定的.

有的button触发 行为a(), 有些触发行为b()

所以, 我们让行为b()写成回调方法, 也就是所让它所需的类实现 回调接口ActionListener().


这样, 就可以很灵活地为每1个button定义不同的触发行为了!













































评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nvd11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值