重要声明:本文章仅仅代表了作者个人对此观点的理解和表述。读者请查阅时持自己的意见进行讨论。
一、序
本文将对Java
开发中常常使用到的一种开发技术(监听器
)做一个比较简单、白话一点的简述和讨论。做Java
开发的贤士都知道,这两种开发技术在实际应用中经常被使用到,但是对于刚刚“出山”的贤士们来说,从代码上直接理解起来还是有点吃力。
这种开发方式对初学者来说一直都是一知半解的存在,我想一部分原因应该归咎于在接受这方面知识得时候,对方的描述比较官方,让我们理解起来不是很通透。我将以更为白话一点的语言将这个技术做一个浅显的解释,希望能够对初学的贤士有一点帮助。
二、引入场景
小保是一个零售店老板,有一天,小保有一批货物要送到一家客户去,但由于小保人手不够,自己又要看店,只好找一个人帮他将这批货物送到客户家里去。通过关系,小保找到了一个派送师傅,并嘱托派送师傅,货物送到了的时候,要第一时间通知小保, 为了能够让通知信息及时送到,小保还给了派送师傅一个对讲机(信号范围覆盖4个星系,滑稽)。
派送师傅很快就取到了货物,开着小电瓶开始送货去了,不一会儿,小保这边的对讲机里传来:小保老板,你的货我已经安全送到客户这里了。小保嘴巴一撇,回复到:好,好!谢谢了。
对于这样的情景,我们可以总结出下面一些要点信息:
1、小保提出送货需求。
2、派送师傅执行送货,同时携带对讲机,便于通知小保。
3、小保收到派送成功的消息。
三、要点分析与代码结合
要感谢Java的创始人詹姆斯·高斯林(百度百科),面向对象的Java语言使你可以将上面的现实场景和你的程序代码一一对应起来。
下面就将已程序代码的方式和现实场景结合起来,没有什么东西比贴近生活更容易理解了,相信你也能看懂。
0、准备
小保能够进行这次送货给客户,因为小保是零售店老板,他这儿有客户需要的东西。正是因为小保是老板的前提,才有了接下来的为客户送货的事情能够顺利发生。
同样的,咱们程序为了正常执行,需要先有一个完整的可以开始运行的前提,所以,先准备好需程序测试类。
public class Test {
// main 方法是每一个java程序的入口函数。
public static void main(String[] args) {
// ...
}
}
1、建立配送员
要完成这次货物的配送,需要派送师傅来完成,所以,必不可少的需要建立一个派送师傅类出来,使用 Transporter 类来表示:
public class Test {
// 派送师傅类。
static class Transporter {
}
public static void main(String[] args) {
// ...
}
}
同时,派送员有一个送东西的功能:
public class Test {
// 派送师傅类。
static class Transporter {
// 添加送东西的功能。
public void sendGood(String goodName) {
System.out.println("正在配送:" + goodName);
}
}
public static void main(String[] args) {
// ...
}
}
现在,你可以做一个测试了,在 main
方法 new
一个派送员,然后进行派送:
public static void main(String[] args) {
Transporter transMan = new Transporter();
// 使用new 出来的派送师傅进行商品派送。
transMan.sendGood("娃哈哈");
}
2、携带对讲机
如果整个需求就如上面的代码就完成了的话,那这个世界岂不大乱。派送员拿着“娃哈哈”灰溜溜的就走了,送到没送到,我也不知道。小保是要保证货品必须到达客户手中的,为了确信这件事,小保特地给了派送员一个对讲机。程序也不例外,要知道 Transporter
到底
有没有将货物送到,也要加入对讲机,这里使用BBtalk
类进行对讲机的模拟,继续完善整个Test
类的代码:
public class Test {
// 派送师傅类。
/* {...} 此处为了节省篇幅已隐藏,实际运行请不要这样写,下同 */
// 对讲机类
static class BBtalk {
// 对讲机有传话功能
public void speak(String word) {
System.out.println(word);
}
}
public static void main(String[] args) {
// ...
}
}
对讲机有了,现在可以将对讲机交给派送师傅了,在程序里,需要为派送师傅类添加一个可以变量用来保存对讲机,同时,让派送师傅在派送成功后使用对讲机传话:
public class Test {
// 派送师傅类。
static class Transporter {
// 对讲机变量。
BBtalk bBtalk;
// 构造函数初始化对讲机
Transporter(BBtalk bBtalk) {
this.bBtalk = bBtalk;
}
// 送东西的功能。
public void sendGood(String goodName) {
System.out.println("正在配送:" + goodName);
// 配送完成,使用对讲机传话。
bBtalk.speak(goodName + ",已经成功送到!");
}
}
// 对讲机类
/* {...} */
public static void main(String[] args) {
// ...
}
}
现在,配送员送完货之后咱们知道了送货员什么时候送到了,写上测试:
public class Test {
// 派送师傅类。
/* {...} */
// 对讲机类
/* {...} */
public static void main(String[] args) {
// 建立对讲机
BBtalk bBtalk = new BBtalk();
// 建立配送师傅,同时将对讲机交给配送师傅。
Transporter transMan = new Transporter(bBtalk);
// 配送师傅进行配送。
transMan.sendGood("娃哈哈");
}
}
3、小结
在上面的整个过程中BBtalk
就充当监听器,Transporter
充当被监听的东西。派送员一但派送完成,就用对讲机传话。被监听的一但完成某操作,就调用监听器的方法,这就叫回调
(通常是以监听器的角度来说,这就叫回调
),BBtalk
的speak
方法称之为[回调方法]
。但是在实际开发中,通常不会为一个监听器专门写一个类,而是以一个接口的方式出现。
继续修改代码,实现技能到应用,添加派送监听器:
public class Test {
// 派送师傅类。
static class Transporter {
// 对讲机变量。 - 不再使用对讲机。
// BBtalk bBtalk;
// 使用监听器
TransportListener transportListener;
// 构造函数初始化对讲机 - 对讲机也别初始化了。
// Transporter(BBtalk bBtalk) {
// this.bBtalk = bBtalk;
// }
// 使用监听器初始化。
Transporter(TransportListener transportListener) {
this.transportListener = transportListener;
}
// 送东西的功能。
public void sendGood(String goodName) {
System.out.println("正在配送:" + goodName);
// 配送完成,使用对讲机传话。 - 不使用对讲机传话了。
// bBtalk.speak(goodName + ",已经成功送到!");
// 使用监听器,调起货物派送完成回调方法
this.transportListener.onTransSuccess(goodName);
}
}
// 对讲机类
/* {...} */
// 派送监听器接口。
interface TransportListener {
// 当货物派送完成,调用该方法。
void onTransSuccess(String goodName);
}
public static void main(String[] args) {
// ..
}
}
使用了监听器,下面再一次进行测试:
public class Test {
// 派送师傅类。
/* {...} */
// 对讲机类
/* {...} */
// 派送监听器接口。
/* {...} */
public static void main(String[] args) {
// 构建派送师傅。
// 由于监听器是一个接口了,此处必须实现该接口中的方法。
// 所以,构建一个匿名内部类,直接传入构造函数。
Transporter transMan = Transporter(new TransportListener() {
// 当派送完成时,此方法会调起。
public void onTransSuccess(String goodName) {
System.out.println(goodName + ",已派送成功!");
}
});
// 派送员进行派送
transMan.sendGood("娃哈哈");
}
}
Perfect!
四、总结
对监听器的理解多多少少有一点接口-interface
方面的知识,在了解了接口相关知识后,理解相对简单。万变不离其中,都是一句话:要调用某个方法,就要拿到这个对象,要有这个对象,就要有地方让别人能为这个对象赋值!