设计模式之回调模式

发布于:2025-07-16 ⋅ 阅读:(15) ⋅ 点赞:(0)

目录

一、同步回调

1. 接口回调

2. 函数式接口

(1) 使用Lambda表达式

(2) 使用方法引用

二、异步回调

1. Future模式

2. CompletableFuture

三、Stream API回调

1. Stream API实现回调

四 回调方案对比分析


回调(Callback)是一种重要的程序设计模式,其核心思想是"反向调用"。在传统调用关系中,A类调用B类的方法;而在回调模式中,A类将自身的引用或方法传递给B类,由B类在特定事件发生时"回调"A类的方法。这种模式实现了控制反转(IoC),遵循"Don't call us, we'll call you"的原则。

回调的本质是行为参数化,将代码作为参数传递执行。它解耦了调用方和被调用方,使系统具备更好的扩展性和灵活性。在事件驱动编程、异步处理、框架设计中广泛应用。

  • 通用架构类图

从技术实现看,回调需要三个基本组件:

  1. 回调接口:定义回调契约

  2. 调用者:持有回调引用并在适当时机触发

  3. 实现者:提供具体回调逻辑

一、同步回调

同步回调中,调用线程会等待回调执行完成后再继续执行,整个流程是阻塞式的。

1. 接口回调

实现原理: 通过定义回调接口,创建匿名内部类实现接口方法

示例代码

// 回调接口
interface Callback {
    void onComplete(String result);
}
​
// 调用者
class FileProcessor {
    private Callback callback;
    
    public void registerCallback(Callback callback) {
        this.callback = callback;
    }
    
    public void processFile(String filename) {
        System.out.println("开始处理文件: " + filename);
        // 模拟处理耗时
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        
        String result = "处理完成: " + filename;
        // 触发回调
        callback.onComplete(result);
    }
}
​
// 客户端
public class TraditionalCallback {
    public static void main(String[] args) {
        FileProcessor processor = new FileProcessor();
        
        // 匿名内部类实现回调
        processor.registerCallback(new Callback() {
            @Override
            public void onComplete(String result) {
                System.out.println("[回调通知] " + result);
            }
        });
        
        processor.processFile("data.txt");
    }
}

输出

开始处理文件: data.txt
[回调通知] 处理完成: data.txt

2. 函数式接口

Java 8的函数式接口(单抽象方法接口)为回调提供了更简洁的实现方式。

(1) 使用Lambda表达式

实现原理: 利用Lambda表达式替代匿名内部类

示例代码

// 使用java.util.function中的标准接口
import java.util.function.Consumer;
​
class ModernFileProcessor {
    // 使用Consumer作为回调接口
    private Consumer<String> callback;
    
    public void setCallback(Consumer<String> callback) {
        this.callback = callback;
    }
    
    public void process(String filename) {
        System.out.println("处理文件: " + filename);
        // 模拟处理
        try { Thread.sleep(800); } catch (Exception e) {}
        
        String result = "SUCCESS: " + filename;
        callback.accept(result);
    }
}
​
public class LambdaCallback {
    public static void main(String[] args) {
        ModernFileProcessor processor = new ModernFileProcessor();
        
        // Lambda实现回调
        processor.setCallback(result ->  System.out.println("回调结果: " + result));
        
        processor.process("report.docx");
    }
}

优势

  • 代码简洁(减少50%代码量)

  • 消除样板代码

  • 类型自动推断

(2) 使用方法引用

实现原理:直接引用已有方法作为回调实现

示例代码

// 使用java.util.function中的标准接口
import java.util.function.Consumer;
​
class ModernFileProcessor {
    // 使用Consumer作为回调接口
    private Consumer<String> callback;
    
    public void setCallback(Consumer<String> callback) {
        this.callback = callback;
    }
    
    public void process(String filename) {
        System.out.println("处理文件: " + filename);
        // 模拟处理
        try { Thread.sleep(800); } catch (Exception e) {}
        
        String result = "SUCCESS: " + filename;
        callback.accept(result);
    }
}
​
public class MethodReferenceCallback {
    public static void main(String[] args) {
        ModernFileProcessor processor = new ModernFileProcessor();
        
        // 方法引用实现回调
        processor.setCallback(MethodReferenceCallback::handleResult);
        
        processor.process("image.png");
    }
    
    // 匹配Consumer的函数签名
    private static void handleResult(String result) {
        System.out.println("处理结果: " + result);
        System.out.println("日志记录: " + result);
    }
}

适用场景

  • 已有方法与回调签名匹配

  • 需要复用现有方法

  • 回调逻辑较复杂需单独封装


二、异步回调

异步回调中,调用线程不等待回调完成,实现非阻塞式处理。

1. Future模式

实现原理: 通过Future获取异步操作结果,需主动轮询或阻塞等待

示例代码

import java.util.concurrent.*;
​
public class FutureCallback {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        
        Future<String> future = executor.submit(() -> {
            System.out.println("异步任务开始");
            Thread.sleep(1500);
            return "处理结果";
        });
        
        // 阻塞获取结果
        String result = future.get();
        System.out.println("获取结果: " + result);
        
        executor.shutdown();
    }
}

缺点

  • get()方法阻塞线程

  • 多任务协调复杂

  • 异常处理不直观

2. CompletableFuture

实现原理:通过CompletionStage链式调用实现非阻塞回调

示例代码

import java.util.concurrent.*;
​
public class CompletableFutureDemo {
    public static void main(String[] args) {
        // 异步执行任务
        CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务开始 - " + Thread.currentThread().getName());
            try { Thread.sleep(1000); } catch (Exception e) {}
            if (Math.random() > 0.5) {
                throw new RuntimeException("模拟异常");
            }
            return "处理结果";
        })
        // 结果处理回调
        .thenAccept(result -> System.out.println("结果回调: " + result))
        // 异常处理回调
        .exceptionally(ex -> {
            System.out.println("错误处理: " + ex.getMessage());
            return null;
        });
        
        System.out.println("主线程继续执行");
        // 防止主线程退出
        try { Thread.sleep(2000); } catch (Exception e) {}
    }
}

核心方法

方法 描述
supplyAsync() 异步执行有返回值的任务
thenApply() 结果转换处理
thenAccept() 消费结果
thenRun() 结果无关的操作
exceptionally() 异常处理
thenCompose() 任务链组合

三、Stream API回调

Stream API通过函数式操作实现集合处理回调。

1. Stream API实现回调

实现原理: 将回调逻辑嵌入Stream操作链中

示例代码

import java.util.stream.*;
​
public class StreamCallback {
    public static void main(String[] args) {
        List<String> files = List.of("doc1", "img2", "report3");
        
        files.stream()
            .filter(name -> name.startsWith("img"))
            .map(name -> {
                System.out.println("处理: " + name);
                return "转换_" + name.toUpperCase();
            })
            .forEach(result -> System.out.println("结果: " + result));
    }
}

关键操作

  • filter():过滤条件回调

  • map():元素转换回调

  • forEach():结果消费回调

  • peek():中间操作回调


四 回调方案对比分析

回调类型 实现方式 线程模型 复杂度 异常处理 适用场景
同步接口回调 接口+匿名类 同步阻塞 直接捕获 简单回调,兼容性要求
Lambda回调 函数式接口+Lambda 同步阻塞 直接捕获 简洁回调,Java8+环境
方法引用 函数式接口+方法引用 同步阻塞 直接捕获 复用现有方法
Future ExecutorService+Future 异步阻塞 特殊处理 简单异步任务
CompletableFuture 链式调用 异步非阻塞 链式处理 复杂异步流程,响应式编程
Stream API Stream操作链 同步/并行 链式处理 集合处理,数据管道

  • 回调模式应用场景

    1. 事件监听机制

    2. 模板方法模式

    3. 异步任务通知

    4. 分布式系统回调

    5. 自定义工作流引擎

    回调模式通过反转控制关系实现了组件间的松耦合,是现代框架设计的基石。随着函数式编程的普及,Lambda和CompletableFuture已成为Java回调的主流实现方式,开发者应根据具体场景选择最合适的实现方案。


网站公告

今日签到

点亮在社区的每一天
去签到