Interpretation of Java Callback Mechanism

https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247484961&idx=1&sn=4377d2648ef964e6b2b9cac951c8564d&chksm=ebd6390ddca1b01b1b8fe222af6ac6bd608d6de66423385481f0c09b29a4a75bc33ee9078005&mpshare=1&scene=1&srcid=0227HkGJ75oxDrnPTkOqZ7xi&key=7a4fd26cfac6ce053526ddd6de3dbf542f17bcda83f469f9ff47c4e121e768438fd407353d0fd7039f3597b4b5667a3835a4b9346fbd888582a08c8fcce8dec84a105b6d59deb0c4b5baef52f0954ec6&ascene=0&uin=MTA2NzUxMDAyNQ%3D%3D&devicetype=iMac+MacBookAir6%2C2+OSX+OSX+10.10.5+build(14F2511)&version=11020012&lang=zh_CN&pass_ticket=Wfg0is1gjKizu056klK%2FVvDzSaRGA%2FawJJ4971k4Ko9crh4ItjtM2smSw0arZ24d


call between modules

In an application system, no matter what language is used for development, there must be calls between modules. There are several ways of calling:

(1) Synchronous call

Synchronous call is the most basic and easiest way to call. The method a() of class A calls the method b() of class B, and waits until the b() method is executed, and the a() method continues to go down. This calling method is suitable for the case where the execution time of the method b() is not long , because if the execution time of the b() method is long or it blocks directly, the rest of the code of the a() method cannot be executed, which will cause the entire process to fail. block.

(2) Asynchronous call

Asynchronous calls are a way of calling to solve the possible blocking of synchronous calls, causing the entire process to get stuck. The method method a() of class A calls the method b() of class B by starting a new thread, and the code is then executed directly , so that no matter how long the execution time of method b() is, method a() will not be blocked implement. However, in this way, since method a() does not wait for the execution of method b() to complete, in the case where method a() requires the execution result of method b() (depending on the specific business, some businesses, such as starting an asynchronous thread to send a message) It is not necessary to notify WeChat and refresh a cache), and the execution result of method b() must be monitored in a certain way. In Java, you can use Future+Callable to do this.

(3) Callback

 

Finally, there is the callback. The idea of ​​the callback is:

  • The a() method of class A calls the b() method of class B

  • After the b() method of class B is executed, the callback() method of class A is actively called

Such a calling method constitutes the above figure, which is a two-way calling method.

 

code example

Next, let's take a look at the code example of the callback. The code simulates such a scenario: the teacher asks the student a question, and the student answers the teacher after thinking.

First define a callback interface, there is only one method tellAnswer(int answer), that is, the student tells the teacher the answer after thinking:

/**
* 回调接口,原文出处http://www.cnblogs.com/xrq730/p/6424471.html
*/

public interface Callback {

   public void tellAnswer(int answer);
   
}


Define a teacher object that implements the Callback interface:

/**
* 老师对象,原文出处http://www.cnblogs.com/xrq730/p/6424471.html
*/

public class Teacher implements Callback {

   private Student student;
   
   public Teacher(Student student) {
       this.student = student;
   }
   
   public void askQuestion() {
       student.resolveQuestion(this);
   }
   
   @Override
   public void tellAnswer(int answer) {
       System.out.println("知道了,你的答案是" + answer);
   }
   
}


The teacher object has two public methods:

(1) Callback interface tellAnswer(int answer), that is, what the teacher has to do after the students answer the questions

(2) The method of asking questions askQuestion(), that is, asking questions to students

接着定义一个学生接口,学生当然是解决问题,但是接收一个Callback参数,这样学生就知道解决完毕问题向谁报告:

/**
* 学生接口,原文出处http://www.cnblogs.com/xrq730/p/6424471.html
*/

public interface Student {
   
   public void resolveQuestion(Callback callback);
   
}


最后定义一个具体的学生叫Ricky:

/**
* 一个名叫Ricky的同学解决老师提出的问题
*/

public class Ricky implements Student {

   @Override
   public void resolveQuestion(Callback callback) {
       // 模拟解决问题
       try {
           Thread.sleep(3000);
       } catch (InterruptedException e) {
           
       }
       
       // 回调,告诉老师作业写了多久
       callback.tellAnswer(3);
   }

}


在解决完毕问题之后,第16行向老师报告答案。

写一个测试类,比较简单:

/**
* 回调测试,原文出处http://www.cnblogs.com/xrq730/p/6424471.html
*/

public class CallbackTest {

   @Test
   public void testCallback() 
{
       Student student = new Ricky();
       Teacher teacher = new Teacher(student);
       
       teacher.askQuestion();
       
   }
   
}

代码运行结果就一行:

知道了,你的答案是3


简单总结、分析一下这个例子就是:

(1)老师调用学生接口的方法resolveQuestion,向学生提问

(2)学生解决完毕问题之后调用老师的回调方法tellAnswer

这样一套流程,构成了一种双向调用的关系。

 

代码分析

分析一下上面的代码,上面的代码我这里做了两层的抽象:

(1)将老师进行抽象

  • 将老师进行抽象之后,对于学生来说,就不需要关心到底是哪位老师询问我问题,只要我根据询问的问题,得出答案,然后告诉提问的老师就可以了,即使老师换了一茬又一茬,对我学生而言都是没有任何影响的

(2)将学生进行抽象

  • 将学生进行抽象之后,对于老师这边来说就非常灵活,因为老师未必对一个学生进行提问,可能同时对Ricky、Jack、Lucy三个学生进行提问,这样就可以将成员变量Student改为List<Student>,这样在提问的时候遍历Student列表进行提问,然后得到每个学生的回答即可

这个例子是一个典型的体现接口作用的例子,之所以这么说是因为我想到有些朋友可能不太明白接口的好处,不太明白接口好处的朋友可以重点看一下这个例子,多多理解。

总结起来,回调的核心就是回调方将本身即this传递给调用方,这样调用方就可以在调用完毕之后告诉回调方它想要知道的信息。回调是一种思想、是一种机制,至于具体如何实现,如何通过代码将回调实现得优雅、实现得可扩展性比较高,一看开发者的个人水平,二看开发者对业务的理解程度。

 

同步回调与异步回调

上面的例子,可能有人会提出这样的疑问:

这个例子需要用什么回调啊,使用同步调用的方式,

学生对象回答完毕问题之后直接把回答的答案返回给老师对象不就好了?

这个问题的提出没有任何问题,可以从两个角度去理解这个问题。

首先,老师不仅仅想要得到学生的答案怎么办?可能这个老师是个更喜欢听学生解题思路的老师,在得到学生的答案之前,老师更想先知道学生姓名和学生的解题思路,当然有些人可以说,那我可以定义一个对象,里面加上学生的姓名和解题思路不就好了。这个说法在我看来有两个问题:

(1)如果老师想要的数据越来越多,那么返回的对象得越来越大,而使用回调则可以进行数据分离,将一批数据放在回调方法中进行处理,至于哪些数据依具体业务而定,如果需要增加返回参数,直接在回调方法中增加即可

(2)无法解决老师希望得到学生姓名、学生解题思路先于学生回答的答案的问题

因此我认为简单的返回某个结果确实没有必要使用回调而可以直接使用同步调用,但是如果有多种数据需要处理且数据有主次之分,使用回调会是一种更加合适的选择,优先处理的数据放在回调方法中先处理掉。

另外一个理解的角度则更加重要,就是标题说的同步回调和异步回调了。例子是一个同步回调的例子,意思是老师向Ricky问问题,Ricky给出答案,老师问下一个同学,得到答案之后继续问下一个同学,这是一种正常的场景,但是如果我把场景改一下:

老师并不想One-By-One这样提问,

而是同时向Ricky、Mike、Lucy、Bruce、Kate五位同学提问,

让同学们自己思考,哪位同学思考好了就直接告诉老师答案即可。

这种场景相当于是说,同学思考完毕完毕问题要有一个办法告诉老师,有两个解决方案:

(1)使用Future+Callable的方式,等待异步线程执行结果,这相当于就是同步调用的一种变种,因为其本质还是方法返回一个结果,即学生的回答

(2)使用异步回调,同学回答完毕问题,调用回调接口方法告诉老师答案即可。由于老师对象被抽象成了Callback接口,因此这种做法的扩展性非常好,就像之前说的,即使老师换了换了一茬又一茬,对于同学来说,只关心的是调用Callback接口回传必要的信息即可


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324818052&siteId=291194637