序言
CallBack是回呼的意思,熟悉Windows程式設計的人對"回呼函數"這四個字一定不會陌生,但是Java程式設計師對它可能就不太了解了。 "回呼函數"或"回呼方法"是軟體設計與開發中一個非常重要的概念,掌握"回呼函數"的思想對程式設計師來說(不管用哪種語言)是非常必要的。
最近學習java,接觸到了回呼機制(CallBack)。初識時感覺比較混亂,而且在網路上搜尋到的相關的講解,要嘛一言帶過,要嘛說的比較單純的像是給CallBack做了一個定義。當然了,我在理解了回調之後,再去看網路上的各種講解,確實沒什麼問題。但是,對於初學的我來說,缺了一個循序漸進的過程。此處,將我對回調機制的個人理解,按照由淺到深的順序描述一下,如有不妥之處,望不吝賜教!
開始之前,先想像一個場景:幼稚園的小朋友剛剛學習了10以內的加法。
第1章. 故事的緣起
幼師在黑板上寫一個式子 “1 + 1 = ”,由小明同學來填空。
由於已經學習了10以內的加法,小明同學可以完全靠自己來計算這個題目,模擬該過程的代碼如下:
public class Student { private String name = null; public Student(String name) { // TODO Auto-generated constructor stub this.name = name; } public void setName(String name) { this.name = name; } private int calcADD(int a, int b) { return a + b; } public void fillBlank(int a, int b) { int result = calcADD(a, b); System.out.println(name + "心算:" + a + " + " + b + " = " + result); } }
小明同學在填空(fillBalnk)的時候,直接心算(
小明同學在填空(fillBalnk)的時候,直接心算(clacADD)了一下,得出結果是2,並將結果寫在空格里。測試程式碼如下:public class Test { public static void main(String[] args) { int a = ; int b = ; Student s = new Student("小明"); s.fillBlank(a, b); } }
運作結果如下:
小明心算:1 + 1 = 2
該過程完全由Student類別的實例物件單獨完成,並未涉及回呼機制。
課間,幼師突發奇想在黑板上寫了「168 + 291 = 」讓小明完成,然後回辦公室了。
花擦!為什麼所有老師都跟小明過不去啊?明明超綱了好不好!這時候小明同學明顯不能再像上面那樣靠心算來完成了,正在懵逼的時候,班上的小紅同學遞過來一個只能計算加法的計算器(奸商啊)! ! ! !而小明同學剛好知道怎麼用計算器,於是透過計算機計算得到結果並完成了填空。
public class Calculator { public int add(int a, int b) { return a + b; } }修改Student類,加入使用計算機的方法:
public class Student { private String name = null; public Student(String name) { // TODO Auto-generated constructor stub this.name = name; } public void setName(String name) { this.name = name; } @SuppressWarnings("unused") private int calcADD(int a, int b) { return a + b; } private int useCalculator(int a, int b) { return new Calculator().add(a, b); } public void fillBlank(int a, int b) { int result = useCalculator(a, b); System.out.println(name + "使用计算器:" + a + " + " + b + " = " + result); } }明使用計算器:168 + 291 = 459
該過程中仍未涉及到回調機制,但是部分小明的部分工作已經實現了轉移,由計算器來協助實現。
3. 幼師回來了public class Test { public static void main(String[] args) { int a = ; int b = ; Student s = new Student("小明"); s.fillBlank(a, b); } }
小明這邊現在已經不需要心算,也不需要使用計算器了,因此只需要有一個方法可以向小紅尋求幫助就行了,程式碼如下:
public class SuperCalculator { public void add(int a, int b, Student xiaoming) { int result = a + b; xiaoming.fillBlank(a, b, result); } }
測試程式碼如下:
public class Student { private String name = null; public Student(String name) { // TODO Auto-generated constructor stub this.name = name; } public void setName(String name) { this.name = name; } public void callHelp (int a, int b) { new SuperCalculator().add(a, b, this); } public void fillBlank(int a, int b, int result) { System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result); } }
1757627627672767237672000322:00176299:03876272729283232323233分7: 計算小= 43036
執行流程為:小明透過自身的callHelp方法呼叫了小紅(new SuperCalculator())的add方法,在呼叫的時候將自身的引用(this)當做參數一併傳入,小紅在使用計算機得出結果之後,回調了小明的fillBlank方法,將結果填在了黑板上的空格里。燈燈燈!到這裡,回呼功能就正式登場了,小明的fillBlank方法就是我們常說的回呼函數。
透過這種方式,可以很明顯的看出,對於完成老師的填空題這個任務上,小明已經不需要等待到加法做完且結果填寫在黑板上才能去跟小伙伴們撒歡了,填空這個工作由超級計算器小紅來做了。回調的優勢已經開始體現了。第4章. 門口的婆婆
幼稚园的门口有一个头发花白的老婆婆,每天风雨无阻在那里摆着地摊卖一些快过期的垃圾食品。由于年纪大了,脑子有些糊涂,经常算不清楚自己挣了多少钱。有一天,她无意间听到了小明跟小伙伴们吹嘘自己如何在小红的帮助下与幼师斗智斗勇。于是,婆婆决定找到小红牌超级计算器来做自己的小帮手,并提供一包卫龙辣条作为报酬。小红经不住诱惑,答应了。
回看一下上一章的代码,我们发现小红牌超级计算器的add方法需要的参数是两个整型变量和一个Student对象,但是老婆婆她不是学生,是个小商贩啊,这里肯定要做修改。这种情况下,我们很自然的会想到继承和多态。如果让小明这个学生和老婆婆这个小商贩从一个父类进行继承,那么我们只需要给小红牌超级计算器传入一个父类的引用就可以啦。
不过,实际使用中,考虑到java的单继承,以及不希望把自身太多东西暴漏给别人,这里使用从接口继承的方式配合内部类来做。
换句话说,小红希望以后继续向班里的小朋友们提供计算服务,同时还能向老婆婆提供算账服务,甚至以后能够拓展其他人的业务,于是她向所有的顾客约定了一个办法,用于统一的处理,也就是自己需要的操作数和做完计算之后应该怎么做。这个统一的方法,小红做成了一个接口,提供给了大家,代码如下:
public interface doJob { public void fillBlank(int a, int b, int result); }
因为灵感来自帮小明填空,因此小红保留了初心,把所有业务都当做填空(fillBlank)来做。
同时,小红修改了自己的计算器,使其可以同时处理不同的实现了doJob接口的人,代码如下:
public class SuperCalculator { public void add(int a, int b, doJob customer) { int result = a + b; customer.fillBlank(a, b, result); } }
小明和老婆婆拿到这个接口之后,只要实现了这个接口,就相当于按照统一的模式告诉小红得到结果之后的处理办法,按照之前说的使用内部类来做,代码如下:
小明的:
public class Student { private String name = null; public Student(String name) { // TODO Auto-generated constructor stub this.name = name; } public void setName(String name) { this.name = name; } public class doHomeWork implements doJob { @Override public void fillBlank(int a, int b, int result) { // TODO Auto-generated method stub System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result); } } public void callHelp (int a, int b) { new SuperCalculator().add(a, b, new doHomeWork()); } }
老婆婆的:
public class Seller { private String name = null; public Seller(String name) { // TODO Auto-generated constructor stub this.name = name; } public void setName(String name) { this.name = name; } public class doHomeWork implements doJob { @Override public void fillBlank(int a, int b, int result) { // TODO Auto-generated method stub System.out.println(name + "求助小红算账:" + a + " + " + b + " = " + result + "元"); } } public void callHelp (int a, int b) { new SuperCalculator().add(a, b, new doHomeWork()); } }
测试程序如下:
public class Test { public static void main(String[] args) { int a = ; int b = ; int c = ; int d = ; Student s = new Student("小明"); Seller s = new Seller("老婆婆"); s.callHelp(a, b); s.callHelp(c, d); } }
运行结果如下:
小明求助小红计算:56 + 31 = 87
老婆婆求助小红算账:26497 + 11256 = 37753元
最后的话
可以很明显的看到,小红已经把这件事情当做一个事业来做了,看她给接口命的名字doJob就知道了。
更多详解 JAVA的回调机制CallBack相关文章请关注PHP中文网!