回调函数与观察者模式(上)

  本文首发于我的微信公众号锋起墨落(javaDeveloper2017),转载请注明出处。

封面拍摄于翼云石头部落,水流推动了水车,水车又反过来推动了水流……

什么是回调函数(callback):

 

 

        维基百科定义: 在计算机程序设计中,回调函数,或简称回调,是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。

 

        这段定义并不容易理解,不同语言的回调也有不同的表现形式,比如C/C++中回调是通过指针的形式实现的,javascript是通过传递函数作为参数来实现的,简单说来,java中的回调函是指一个类调用另一个类的方法,方法执行完成之后被调用者类会反过来调用调用者类方法(回调)的过程。

 

回调函数的作用:

 

 

        程序模块之间的调用大致分为三种,同步调用,回调,以及异步调用。同步调用是阻塞式的,回调模式是一种双向的调用,异步调用可以解决同步阻塞问题。 回调是异步的基础,因此回调不一定用于异步,一般同步(阻塞)的场景下也经常用到回调,比如要求执行某些操作后执行回调函数。

3经典回调函数示例:

 

 

        我们举一个客户端-服务端(Client-Server)通讯的例子来阐述回调函数。 Client向Server发送一条消息,并立即打印出发送状态(无需等待服务端处理完成),服务端接收消息处理完成后通过回调通知客户端。

 

        首先我们定义一个CallBack接口,接口中backMsg即为回调函数。

1 public interface CallBack {
2     public void  backMsg(String msg);
3 }

  客户端的需要实现回调接口,客户端通过sendMsg发送消息,通过回调函数backMsg来接收返回消息。

  

 1 public class Client implements CallBack {
 2     private Server server;
 3 
 4     public Client(Server server) {
 5         this.server = server;
 6     }
 7 
 8     /**
 9      * 回调函数
10      * @param msg
11      */
12     public void backMsg(String msg) {
13         System.out.println("客户端接收到返回消息:"+msg);
14     }
15 
16     public void sendMsg(final String msg){
17         System.out.println("客户端开始发送消息"+msg);
18         new Thread(new Runnable() {
19             @Override
20             public void run() {
21                 server.receiveMsg(Client.this,msg);
22             }
23         }).start();
24 
25         System.out.println("客户端成功发送消息"+msg);
26     }
27 }

服务端接收消息后使用sleep模拟消息处理耗时,处理完成后回调通知客户端。

 1 public class Server {
 2     public Server() {
 3     }
 4 
 5     public void receiveMsg(CallBack callBack, String msg) {
 6         System.out.println("服务器接收到客户端消息:" + msg);
 7         try {
 8             Thread.sleep(5000);
 9         } catch (InterruptedException e) {
10             e.printStackTrace();
11         }
12         String backMsg = "你好,客户端!";
13         System.out.println("服务器处理成功,返回消息:" + backMsg);
14         callBack.backMsg(backMsg);
15     }
16 }

 我们看到java中回调是通过CallBack接口来实现的,(当然也可以不使用接口,但使用接口的优点 就不用多说了吧),Client实现接口并在调用时发送自身引用(Client.this),Server通过引用来调用回调函数。可以写个测试类测试下:

1 public class CallBackTest {
2     public static void main(String[] args) {
3         Client client = new Client(new Server());
4         client.sendMsg("你好,服务端!");
5     }
6 }

  


运行结果:
客户端开始发送消息你好,服务端!
客户端成功发送消息你好,服务端!
服务器接收到客户端消息:你好,服务端!
服务器处理成功,返回消息:你好,客户端!
客户端接收到返回消息:你好,客户端!
 

  我们可以看到通过回调,我们避免了同步阻塞。

 

  下期我们将通过一个故事介绍观察者模式,以及和回调函数之间的关系。

 

 

  

原文地址:https://www.cnblogs.com/lkxsnow/p/7577091.html