软件设计不是CRUD(16):低耦合模块设计理论——行为抽象与设计模式(下)

(接上文《软件设计不是CRUD(15):低耦合模块设计理论——行为抽象与设计模式(中)》)

3.2.4、之前的业务逻辑需要关注后续逻辑的执行成败,并调整自身执行的情况

这个场景在之前场景的基础上增加了新的控制要求,具体来说就是之前已经完成的控制逻辑执行,需要在后续控制逻辑执行出现问题时,获得一种错误补偿的方式。这和我们常说的数据库事务还有所区别(当然数据库事务回滚也是必要的一种错误补偿方式),因为错误补偿不一定是数据库事务回滚。

这实际上也是在之前介绍的单个业务控制点的基础上,对一个业务维度的多个实现进行错误补偿控制方式的一种扩充。只不过这里需要解决的是一个控制逻辑上,多个业务控制点之间如何协进行调错误补偿的问题。这里推荐一种命令模式的设计方式,如下图所示:

在这里插入图片描述
为什么这里需要将具体结算单的策略传入到命令中,这是因为不可能为某一种具体的结算单创建一种对应的命令,例如不可能为SettlementA这种类型的结算单创建专门的一种转换命令,然后再为SettlementB这种类型的结算单创建专门的一种转换命令,否则可能会导致类爆炸(类爆炸的概念在前文中介绍过,这里不再赘述,导致类爆炸的原因主要是因为维度合并,且设计无法控制维度扩展)。

  • 这是命令接口的定义
// 结算单执行命令
public interface SettlementCommand {
   
  // 命令执行方法
  public void doCommand();
  // 用于在控制逻辑出现错误的情况下
  // 要求具体命令的业务执行过程进行错误补偿
  public void redo(Throwable e);
}
  • 对结算单信息进行验证的命令
// 对结算单信息进行验证的命令
public class ValidateSettlementCommand implements SettlementCommand {
   
  private SettlementStrategy<Settlement> settlementStrategy;
  private Settlement settlement;
  
  // =======
  // 这里有一个构造方法,为了节约篇幅省去
  // =======
  
  @Override
  public void doCommand() {
   
    if(this.settlementStrategy.needValidate(settlement)) {
   
      this.settlementStrategy.validate(settlement);
    }
  }
  @Override
  public void redo() {
   
    // 该验证命令在整个控制逻辑出现问题时,不用做对应的错误补偿
  }
}
  • 对结算单信息进行信息转换的命令
// 对结算单信息进行信息转换的命令
public class BalanceSettlementCommand implements SettlementCommand {
   
  private SettlementStrategy<Settlement> settlementStrategy;
  private BalanceStrategy balanceStrategy;
  private Settlement settlement;
  
  // =======
  // 这里有一个构造方法,为了节约篇幅省去
  // =======
  
  @Override
  public void doCommand() {
   
    this.settlementStrategy.balance(settlement, balanceStrategy);
  }
  @Override
  public void redo() {
   
    // 当整个控制逻辑发生错误时,该命令需求重置已设定的结算费用,并清理数据库中的设定信息
  }
}
  • 发送事件通知的命令
// 发送事件通知的命令
@Slf4j
public class SendEventSettlementCommand implements SettlementCommand {
   
  private Settlement settlement;
  @Autowired(required = false)
  private List<SettlementEventListener> settlementEventListeners;
  public SendEventSettlementCommand(Settlement settlement) {
   
    this.settlement = settlement;
  }
  
  @Override
  public void doCommand() {
   
    if(CollectionUtils.isEmpty(this.settlementEventListeners)) {
   
      return;
    }
    // 对上层模块进行事件通知
    for (SettlementEventListener settlementEventListener : settlementEventListeners) {
   
      try {
   
        settlementEventListener.onBalanced(settlement);
      } catch(RuntimeException e) {
   
        log.error(e.getMessage() , e);
      }
    }
  }
  
  @Override
  public void redo() {
   
    

最近更新

  1. TCP协议是安全的吗?

    2024-03-30 09:10:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-30 09:10:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-30 09:10:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-30 09:10:01       18 阅读

热门阅读

  1. 数据可视化之折线图plot

    2024-03-30 09:10:01       17 阅读
  2. C++智能指针简单剖析

    2024-03-30 09:10:01       18 阅读
  3. 汽车VBF格式文件详解---使用python解析VBF文件

    2024-03-30 09:10:01       16 阅读
  4. pandas中mode() 函数的应用

    2024-03-30 09:10:01       17 阅读
  5. rust - 使用文件锁防止应用多开

    2024-03-30 09:10:01       23 阅读
  6. Android 使用SQLite保存数据

    2024-03-30 09:10:01       18 阅读
  7. #设计模式#3.1 抽象工厂

    2024-03-30 09:10:01       15 阅读