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


      本文首发于我的微信公众号锋起墨落(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 }

      

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

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

     

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

     

     

      

  • 相关阅读:
    计算属性(computed)、方法(methods)和侦听属性(watch)的区别与使用场景
    DatagramChannel
    IIS发布问题集锦
    ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象
    MVC教程--MiniProfiler.EF监控调试MVC和EF的性能
    关于EF输出sql的执行日志
    Entity Framework扩展库
    C#中特性,以及应用场景(收藏链接)
    ajax原理
    .net中session无效
  • 原文地址:https://www.cnblogs.com/lkxsnow/p/7577091.html
Copyright © 2020-2023  润新知