tortelee

导航

 

偶然看到一篇文章, https://www.cnblogs.com/buguge/p/19055703
对这篇文章的设计进行了更改。

原来设计的类图 和流程图 :

deepseek_mermaid_20250921_877646

deepseek_mermaid_20250921_bb29b5

原有设计的优缺点:

优点
实现了解耦

  • 核心优势:业务层(插件)不依赖于上层应用的具体实现,而是依赖于一个抽象的接口 (TransferCallback)。这符合依赖倒置原则 (DIP),是插件化架构的基石。

  • 灵活性:上层应用可以自由决定是否关心回调事件(通过选择是否实现接口并注入),以及如何响应事件(在 onTransferSuccess 方法中实现任何业务逻辑)。

对应用层封装了异步复杂性

异步线程的创建、管理和任务提交完全由业务层(AccountTransferService)内部完成。上层应用只需调用一个同步风格的 accounting() 方法,无需关心其内部是多线程实现的,简化了调用方的使用。

“一站式”服务

对于上层应用来说,它只需要与 AccountTransferService 打交道。它既通过这个服务执行了转账操作,也通过它获得了操作完成的通知。如果不需要通知,甚至不需要感知 TransferCallback 接口的存在。这在简单场景下显得非常简洁。

缺点
破坏了单一职责原则 (SRP)

  • 核心问题:AccountTransferService 承担了过多的职责。它不仅是“转账业务”的执行者,还是“异步任务”的管理者,同时又是“事件”的发布者。这导致其职责不纯粹、不单一,变得臃肿,违反了高内聚的设计目标。

隐藏的控制流和调试困难

  • 回调函数使得程序的执行流程变得不直观。当阅读 AccountTransferService 的代码时,无法直接看出 transferCallback.onTransferSuccess() 最终会执行哪段代码,必须去查找被注入的具体实现是什么。

  • 当回调函数中出现 bug 时,栈追踪信息会分散在两个不同的线程和模块中,增加了定位问题的难度。

有限的灵活性和可复用性

  • 强绑定通知机制:业务层强制规定了通知的机制(同步回调)。如果上层应用希望用事件总线、消息队列等其他方式来处理通知,将无法实现,除非修改业务层代码。

  • 无法选择同步执行:业务层硬编码了异步逻辑。如果某个场景下希望同步等待转账完全完成后再继续,这个设计无法满足。

  • 复用性差:如果想在另一个不需要通知的项目中复用 AccountTransferService,会发现它依然拖着异步线程池和回调检查的逻辑,无法作为一个纯净的业务组件使用。

生命周期和并发管理复杂

  • 业务层需要自己管理线程池 (ExecutorService) 的生命周期(创建、关闭),这增加了其复杂度。

  • 在回调应用中,需要考虑线程安全问题。如果多个线程可能同时修改回调函数引用(通过 setter),需要做同步处理。

错误处理机制不完善

  • 原始设计只考虑了成功回调 (onTransferSuccess),没有定义失败回调。一个健壮的系统必须考虑异步操作可能失败的情况,而原有设计在这方面是缺失的。

新的设计:

deepseek_mermaid_20250921_d1b79a
deepseek_mermaid_20250921_7c6752

业务层(插件层)- 纯粹的同步逻辑

// 转账结果类
public class TransferResult {
    private final String transferOrderNo;
    private final boolean success;
    private final String message;
    
    public TransferResult(String transferOrderNo, boolean success, String message) {
        this.transferOrderNo = transferOrderNo;
        this.success = success;
        this.message = message;
    }
    
    // Getters
    public String getTransferOrderNo() { return transferOrderNo; }
    public boolean isSuccess() { return success; }
    public String getMessage() { return message; }
    
    @Override
    public String toString() {
        return "TransferResult{" +
                "transferOrderNo='" + transferOrderNo + '\'' +
                ", success=" + success +
                ", message='" + message + '\'' +
                '}';
    }
}

// 账户转账服务 - 纯粹的业务逻辑,完全同步
public class AccountTransferService {
    private final AccountingService accountingService = new AccountingService();
    
    // 同步执行转账,不包含任何异步或通知逻辑
    public TransferResult accountingSync(AccountTransfer accountTransfer) {
        System.out.println("转账记账开始 - 同步执行");
        
        try {
            // 同步处理转出账户
            AccountingRequest fromRequest = new AccountingRequest(
                accountTransfer.getTransferOrderNo(), 
                accountTransfer.getFrom(), 
                accountTransfer.getTransferAmount(), 
                true
            );
            accountingService.accounting(fromRequest);
            
            // 同步处理收款方
            Map<String, Double> tos = accountTransfer.getTos();
            for (Map.Entry<String, Double> entry : tos.entrySet()) {
                AccountingRequest toRequest = new AccountingRequest(
                    accountTransfer.getTransferOrderNo(),
                    entry.getKey(),
                    entry.getValue(),
                    false
                );
                accountingService.accounting(toRequest);
            }
            
            return new TransferResult(
                accountTransfer.getTransferOrderNo(),
                true,
                "转账成功完成"
            );
        } catch (Exception e) {
            return new TransferResult(
                accountTransfer.getTransferOrderNo(),
                false,
                "转账失败: " + e.getMessage()
            );
        }
    }
}

// 记账服务
public class AccountingService {
    public void accounting(AccountingRequest request) {
        System.out.println("AccountingService->记账完成. " +
                "业务单号=" + request.getOrderNo() +
                ", accountNo=" + request.getAccountNo() +
                ", amount=" + request.getAmount() +
                (request.isFrom() ? " (转出)" : " (转入)"));
    }
}

// 账户转账请求
public class AccountTransfer {
    private String transferOrderNo;
    private String from;
    private double transferAmount;
    private Map<String, Double> tos;
    
    // Getters and setters
    public String getTransferOrderNo() { return transferOrderNo; }
    public AccountTransfer setTransferOrderNo(String transferOrderNo) { 
        this.transferOrderNo = transferOrderNo; 
        return this;
    }
    
    public String getFrom() { return from; }
    public AccountTransfer setFrom(String from) { 
        this.from = from; 
        return this;
    }
    
    public double getTransferAmount() { return transferAmount; }
    public AccountTransfer setTransferAmount(double transferAmount) { 
        this.transferAmount = transferAmount; 
        return this;
    }
    
    public Map<String, Double> getTos() { return tos; }
    public AccountTransfer setTos(Map<String, Double> tos) { 
        this.tos = tos; 
        return this;
    }
}

// 记账请求
public class AccountingRequest {
    private final String orderNo;
    private final String accountNo;
    private final double amount;
    private final boolean isFrom;
    
    public AccountingRequest(String orderNo, String accountNo, double amount, boolean isFrom) {
        this.orderNo = orderNo;
        this.accountNo = accountNo;
        this.amount = amount;
        this.isFrom = isFrom;
    }
    
    // Getters
    public String getOrderNo() { return orderNo; }
    public String getAccountNo() { return accountNo; }
    public double getAmount() { return amount; }
    public boolean isFrom() { return isFrom; }
}
  1. 应用层 - 包含异步和通知逻辑
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// 应用层服务 - 包含异步和通知逻辑
public class TransferOrderService {
    private final AccountTransferService accountTransferService;
    private final ExecutorService executorService;
    
    public TransferOrderService() {
        this.accountTransferService = new AccountTransferService();
        this.executorService = Executors.newFixedThreadPool(3);
    }
    
    // 应用层决定如何使用业务层服务(同步或异步)
    public void transfer() {
        System.out.println("转账单记账 - 应用层");
        
        // 准备转账数据
        AccountTransfer accountTransfer = new AccountTransfer();
        accountTransfer.setTransferOrderNo("T202508000001")
                      .setFrom("A")
                      .setTransferAmount(50.00);
        accountTransfer.setTos(Map.of("B", 10.00, "C", 40.00));
        
        // 应用层决定使用异步方式调用业务层服务
        executorService.submit(() -> {
            try {
                // 调用业务层的同步方法
                TransferResult result = accountTransferService.accountingSync(accountTransfer);
                
                // 应用层处理结果和通知
                if (result.isSuccess()) {
                    onTransferSuccess(result);
                } else {
                    onTransferFailure(result);
                }
            } catch (Exception e) {
                System.err.println("转账过程中发生异常: " + e.getMessage());
                onTransferFailure(new TransferResult(
                    accountTransfer.getTransferOrderNo(),
                    false,
                    "转账异常: " + e.getMessage()
                ));
            }
        });
    }
    
    // 应用层处理成功通知
    public void onTransferSuccess(TransferResult result) {
        System.out.println("=========当前是在应用层,进行转账完成后的业务处理");
        System.out.println("=========已向收款人发送到账通知短消息");
        System.out.println("=========转账结果: " + result);
        
        // 这里可以添加更多的应用层业务逻辑
        // 比如:更新订单状态、发送消息、记录日志等
    }
    
    // 应用层处理失败通知
    public void onTransferFailure(TransferResult result) {
        System.out.println("=========转账失败,执行补偿操作");
        System.out.println("=========失败原因: " + result.getMessage());
        
        // 这里可以添加失败处理逻辑
        // 比如:回滚操作、发送告警等
    }
    
    // 关闭线程池
    public void shutdown() {
        executorService.shutdown();
    }
}
  1. 演示主程序
public class ApplicationDemo {
    public static void main(String[] args) {
        // 创建应用层服务
        TransferOrderService transferOrderService = new TransferOrderService();
        
        // 执行转账
        transferOrderService.transfer();
        
        // 等待异步操作完成
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        // 清理资源
        transferOrderService.shutdown();
    }
}

新版本设计(职责完全分离)的优势与劣势分析

优势 ✅

1. 极致的职责分离与单一职责原则

  • 业务层纯粹性AccountTransferService 只关注核心转账逻辑,不包含任何异步、通知或线程管理代码
  • 应用层专注性TransferOrderService 专门处理业务协调、异步调度和通知逻辑
  • 符合高内聚低耦合:每个模块都有明确且单一的职责,模块间通过清晰接口通信

2. 卓越的可测试性

  • 业务层测试简单:可以轻松测试同步转账逻辑,无需模拟异步环境或回调机制
  • 独立测试:业务层和应用层可以完全独立测试,互不干扰
  • 测试覆盖率提高:清晰的职责边界使得编写单元测试更加直观和全面

3. 高度可复用性

  • 业务层通用性:纯净的同步业务逻辑可以被任何需要转账功能的应用复用
  • 多种使用方式:应用层可以根据需要选择同步或异步调用业务层
  • 框架无关性:业务层不依赖任何特定框架或模式,迁移成本低

4. 更清晰的架构与可维护性

  • 直观的代码流程:执行路径明确,没有隐藏的回调或间接调用
  • 易于理解:新开发者能够快速理解系统结构和数据流
  • 长期维护友好:职责清晰减少代码腐化,便于后续扩展和修改

5. 灵活性与扩展性

  • 通知机制灵活:应用层可以自由选择通知方式(日志、事件、消息队列等)
  • 异步策略可定制:可以轻松实现不同的异步模式(如重试、批处理、熔断等)
  • 易于集成新功能:新增功能只需在适当层级添加,不会影响其他部分

劣势 ❌

1. 应用层复杂度增加

  • 代码冗余风险:每个使用业务层的地方都需要重复实现类似的异步和通知逻辑
  • 开发工作量增加:需要应用层开发者处理更多基础架构 concerns
  • 学习曲线稍陡:开发者需要理解分层架构和职责分离的理念

2. 业务层无法主动通知

  • 被动服务模式:业务层只是功能提供者,无法在特定事件发生时主动通知应用层
  • 实时性受限:对于需要业务层主动推送信息的场景,此模式不适用

3. 可能存在性能开销

  • 数据传递开销:需要通过返回值传递结果,而不是直接回调,可能增加少量数据复制开销
  • 上下文切换:应用层管理异步可能增加线程上下文切换(但通常可忽略)

4. 初期开发效率可能略低

  • 设计决策增多:需要更多前期设计思考,确定哪些逻辑属于业务层,哪些属于应用层
  • 模板代码增加:需要编写更多的"胶水代码"来连接各层

适用场景推荐

适合采用新设计的场景

  • ✅ 大型复杂企业应用系统
  • ✅ 需要高度可测试性和可维护性的项目
  • ✅ 业务逻辑需要被多个应用复用的场景
  • ✅ 长期演进和持续维护的项目
  • ✅ 团队注重代码质量和架构整洁度

可能不适合的场景

  • ❌ 简单的一次性脚本或原型开发
  • ❌ 极度追求开发速度的初创项目MVP阶段
  • ❌ 业务层需要主动推送信息的实时系统
  • ❌ 团队对分层架构理解不足且时间紧迫

总结

新版本设计通过极致的职责分离,牺牲了一定的开发便利性,换来了卓越的可维护性、可测试性和灵活性。这种权衡在大多数企业级应用开发中是值得的,特别是对于需要长期维护和演进的系统。

特性 新版本设计 旧版本设计
职责清晰度 ⭐⭐⭐⭐⭐ ⭐⭐
可测试性 ⭐⭐⭐⭐⭐ ⭐⭐
可复用性 ⭐⭐⭐⭐⭐ ⭐⭐⭐
开发效率 ⭐⭐⭐ ⭐⭐⭐⭐
长期维护 ⭐⭐⭐⭐⭐ ⭐⭐
灵活性 ⭐⭐⭐⭐⭐ ⭐⭐⭐

推荐使用:对于大多数严肃的商业项目,推荐采用新版本设计,因为它为系统的长期健康奠定了更好的架构基础。

posted on 2025-09-21 12:00  tortelee  阅读(37)  评论(1)    收藏  举报