【Java】Java使用回调函数的优雅方式

    技术2022-07-11  131

    Java使用回调函数的优雅方式

    Java8新增了函数式接口,函数式接口中只有一个接口方法,这个接口方法可以与一个静态方法或者某个实例对象的方法进行绑定。通过这种方式,我们可以将一个函数式接口做成一个回调。

    例如有如下场景: 有多台服务器Server,对外提供服务;有一个控制中心Controller,Controller需要统计Server对外提供服务的次数,或者说Server提供了服务需要让Controller得到一个通知。

    现在我们有如下的实现。

    @FunctionalInterface interface WorkTimesCounter { void count(); } class Server { private WorkTimesCounter workTimesCounter; public Server(WorkTimesCounter workTimesCounter) { this.workTimesCounter = workTimesCounter; } public void doWork() { System.out.println("do work..."); workTimesCounter.count(); } } class Controller { int count = 0; public void addCount() { count++; System.out.println("total serve " + count + " times."); } }

    如何使用呢?我们只需要实例化一个WorkTimesCounter,绑定某个实例controller的addCount方法,最后把WorkTimesCounter通过构造函数传入一个Service中。

    public static void main(String[] args) { Controller controller = new Controller(); WorkTimesCounter c = controller::addCount; // 绑定 Server server = new Server(c); for (int i = 0; i < 10; i++) { server.doWork(); } }

    最终的输出:

    Work do... total serve 1 times. Work do... total serve 2 times. Work do... total serve 3 times. Work do... total serve 4 times. Work do... total serve 5 times. Work do... total serve 6 times. Work do... total serve 7 times. Work do... total serve 8 times. Work do... total serve 9 times. Work do... total serve 10 times.

    如果不使用回调?

    Server需要持有Controller对象才能够实现对Controller方法的调用。

    class Server { private Controller controller; public Server(Controller controller) { this.controller = controller; } public void doWork() { System.out.println("do work..."); controller.addCount(); } } class Controller { int count = 0; public void addCount() { count++; System.out.println("total serve " + count + " times."); } }

    这种方式会让Server对Controller产生强依赖,不符合高内聚低耦合的软件设计标准。

    所以使用回调函数可以降低模块之间的耦合程度,同时它也可以实现一些通知的功能、以及在应用程序层面实现异步调用。

    扩展

    NS3是一个网络仿真工具,里面使用了大量的回调函数。NS3采用模块化的设计,将现实网络中的元素意义抽象为一个模块,比如节点、应用层、传输层、网络层、网络接口层、网络链路和节点的移动模型等等,都是根据真实网络环境抽象而来。 在运行仿真时,一个节点对象上面,会聚合应用层、传输层、网络层、网络接口层、网络链路、节点的移动模型这些模块。

    这些模块之间的关系基本上都是上层持有下层,上层可以直接调用下层的接口;而下层不持有上层,下层向上层递交数据的时候也是通过回调函数来实现的。

    Processed: 0.009, SQL: 9