在 Android 系统中,回调几乎随处可见,最常见的就是给点击事件设置监听,如下:
1 2 3 4 5 6 |
btn_login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // TODO log in } }); |
如果你开发过 Android 应用,相信上面的代码你不会陌生。下面就根据我的理解谈一谈啥是回调,为啥使用回调,以及如何在自己的代码中定义回调。
0x00. 什么是回调?
我们先来看一下百度百科中对回调的定义:
回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口。
看不懂?没关系,我们再来看下面这段话:
在面向对象的语言中,回调是通过接口或抽象类来实现的,我们把实现这种接口的类称为回调类,回调类的对象成为回调对象。
我们来把上面两句话归结一下:
回调就是抽象类(或接口)的实例实现父类的抽象方法后,将该方法交还给父类调用。
0x01. 为啥使用回调?
诚如定义中所言:“回调是一种模式”,既然是模式,肯定是为了解决某一类问题而出现的。那么回调解决了什么问题呢?
这里我们引用一下刘济华老师《漫谈设计模式》一书中买车票回家过节的例子:
小明准备坐火车回家:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class XiaoMing { public void celebrateSpringFestival() { // Buy ticket buyTicket(); // Travelling by train travellingByTrain(); // Celebrating Chinese New Year celebrating(); } private void celebrating() {} private void travellingByTrain() {} private void buyTicket() {} } |
而小红离家比较近,她想坐大巴回去,也好办:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class XiaoHong { public void celebrateSpringFestival() { // Buy ticket buyTicket(); // Travelling by bus travellingByBus(); // Celebrating Chinese New Year celebrating(); } private void celebrating() {} private void travellingByBus() {} private void buyTicket() {} } |
细心的你可以发现,两段代码中有相当一部分重复。对于重复代码我们如何去优化呢?是的,使用继承大法。但是,每个人的乘车方式都是不同的,我们无法在基类中作出明确定义,而乘车又是回家过节必需的过程(不考虑离家近的同学步行回家的情况~)。我们只有把乘车方法定义为抽象方法,让各实现类自行决定如何乘车:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public abstract class BeiPiao { public void celebrateSpringFestival() { // Buy ticket buyTicket(); // Travelling by bus travelling(); // Celebrating Chinese New Year celebrating(); } abstract void travelling(); private void celebrating() { System.out.println("celebrating...") } private void buyTicket() { System.out.println("buy ticket...") } } |
在 Android 系统中,回调几乎随处可见,最常见的就是给点击事件设置监听,如下:
1 2 3 4 5 6 |
btn_login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // TODO log in } }); |
如果你开发过 Android 应用,相信上面的代码你不会陌生。下面就根据我的理解谈一谈啥是回调,为啥使用回调,以及如何在自己的代码中定义回调。
0x00. 什么是回调?
我们先来看一下百度百科中对回调的定义:
回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口。
看不懂?没关系,我们再来看下面这段话:
在面向对象的语言中,回调是通过接口或抽象类来实现的,我们把实现这种接口的类称为回调类,回调类的对象成为回调对象。
我们来把上面两句话归结一下:
回调就是抽象类(或接口)的实例实现父类的抽象方法后,将该方法交还给父类调用。
0x01. 为啥使用回调?
诚如定义中所言:“回调是一种模式”,既然是模式,肯定是为了解决某一类问题而出现的。那么回调解决了什么问题呢?
这里我们引用一下刘济华老师《漫谈设计模式》一书中买车票回家过节的例子:
小明准备坐火车回家:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class XiaoMing { public void celebrateSpringFestival() { // Buy ticket buyTicket(); // Travelling by train travellingByTrain(); // Celebrating Chinese New Year celebrating(); } private void celebrating() {} private void travellingByTrain() {} private void buyTicket() {} } |
而小红离家比较近,她想坐大巴回去,也好办:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class XiaoHong { public void celebrateSpringFestival() { // Buy ticket buyTicket(); // Travelling by bus travellingByBus(); // Celebrating Chinese New Year celebrating(); } private void celebrating() {} private void travellingByBus() {} private void buyTicket() {} } |
细心的你可以发现,两段代码中有相当一部分重复。对于重复代码我们如何去优化呢?是的,使用继承大法。但是,每个人的乘车方式都是不同的,我们无法在基类中作出明确定义,而乘车又是回家过节必需的过程(不考虑离家近的同学步行回家的情况~)。我们只有把乘车方法定义为抽象方法,让各实现类自行决定如何乘车:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public abstract class BeiPiao { public void celebrateSpringFestival() { // Buy ticket buyTicket(); // Travelling by bus travelling(); // Celebrating Chinese New Year celebrating(); } abstract void travelling(); private void celebrating() { System.out.println("celebrating...") } private void buyTicket() { System.out.println("buy ticket...") } } |