Su的技术博客

  • 首页
  • 原创
  • 视频
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • AI
  • Other
  • 工具
    • AI工具集
    • 工具清单
    • JSON在线格式化
    • JSON在线比较
    • SQL在线格式化
  • 打赏
  • 关于
路很长,又很短
  1. 首页
  2. Java
  3. 正文
                           

【组合】【进阶玩法】策略+责任链+组合实现合同签章

2024-11-03 1054点热度 0人点赞 0条评论
【进阶玩法】策略+责任链+组合实现合同签章
项目中所用的合同签章处理流程,本人基于责任链模式上使用策略模式进行的优化。

前置内容

  1. 掌握策略模式
  2. 掌握责任链模式
  3. 掌握类继承、接口的实现
  4. 掌握参数的传递与设置
  5. GitHub地址

ps:【文章由来】公司项目中所用的合同签章处理流程,本人基于责任链上使用策略模式进行优化。

签章的处理流程

  1. 合同文本初始化
  2. 合同文本生成
  3. 签章挡板是否开启
  4. 合同签章发送mq
  5. 合同签章流水更新
  6. 合同上传文件服务器
  7. 签章渠道选择
  8. 签章渠道的实际调用

执行的流程如下:
【进阶玩法】策略+责任链+组合实现合同签章

整个结构类似于递归调用。每个节点中依赖上一个节点的输入以及下一个节点的输出,在中间过程可以实现每个节点的自定义操作,比较灵活。

流程实现

GitHub地址

项目结构

DesignPatterns
└── src
    └── main
        └── java
            └── com.xbhog.chainresponsibility
                ├── annotations
                │    └── ContractSign
                ├── channel
                │    ├── ContractSignChannelImpl.java
                │    └── ContractSignChannel
                ├── Config
                │    └── SignConfig
                ├── Enum
                │    └── ContractSignEnum
                ├── impl
                │    ├── ContractSignCompactInitImpl.java
                │    ├── ContractSignGenerateImpl.java
                │    ├── ContractSignMockImpl.java  
                │    ├── ContractSignMqImpl.java
                │    ├── ContractSignSaveUploadImpl.java
                │    ├── ContractSignSerialImpl.java
                │    └── ContractSignTradeImpl.java
                ├── inter
                │    ├── Call
                │    ├── Chain
                │    ├── Interceptor
                │    └── Processor
                ├── pojo
                │    ├── ContractRequest.java
                │    └── ContractResponse.java
                ├── ContractCall
                ├── ContractChain
                └── ContractSignProcessor.java

 

项目类图

【进阶玩法】策略+责任链+组合实现合同签章

责任链+组合模式代码实现

工程结构

DesignPatterns
└── src
    └── main
        └── java
            └── com.xbhog.chainresponsibility
                ├── channel
                │    ├── ContractSignChannelImpl.java
                │    └── ContractSignChannel
                ├── impl
                │    ├── ContractSignCompactInitImpl.java
                │    ├── ContractSignGenerateImpl.java
                │    ├── ContractSignMockImpl.java  
                │    ├── ContractSignMqImpl.java
                │    ├── ContractSignSaveUploadImpl.java
                │    ├── ContractSignSerialImpl.java
                │    └── ContractSignTradeImpl.java
                ├── inter
                │    ├── Call
                │    ├── Chain
                │    ├── Interceptor
                │    └── Processor
                ├── pojo
                │    ├── ContractRequest.java
                │    └── ContractResponse.java
                ├── ContractCall
                ├── ContractChain
                └── ContractSignProcessor.java

 

责任链中的对象定义

//请求
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ContractRequest {
private String name;

private String age;

private String status;

}
//响应
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ContractResponse {
private String status;

private String mas;

}

定义流程中的请求及响应类,方便处理每个责任链的请求、返回信息。

责任链处理流程

/**
 * @author xbhog
 * @describe: 责任链+组合实现合同签章
 * @date 2023/7/11
 */
@Slf4j
@Component
public class ContractSignProcessor  implements Processor {
@Resource(name = "contractSignCompactInitImpl")
private Interceptor contractCompactInitImpl;
......

public ContractSignProcessor() { }

@Override public ContractResponse process(T paramter) { //获取所有的监听器 List> interceptorList = new ArrayList(); interceptorList.add(contractCompactInitImpl); ...... //开始签章 log.info("签章开始"); return new ContractCall(paramter,interceptorList).exectue(); }

}

 

合同签章方法的主流程调用接口(入口),该类中注入所有的节点实现类(如contractCompactInitImpl),通过编排实现责任链流程。
在初始化节点之前,进行节点的封装以及数据请求的处理。例:contractCompactInitImpl-合同数据初始化节点

/**
 * @author xbhog
 * @describe: 合同数据请求、节点的实例化及方法执行
 * @date 2023/7/11
 */
public class ContractCall implements Call {
    private final T originalRequest;
    private final List> interceptorList;
public ContractCall(T originalRequest, List> interceptorList) {
    this.originalRequest = originalRequest;
    this.interceptorList = interceptorList;
}

@Override public T request() { return this.originalRequest; }

@Override public ContractResponse exectue() { //实例化流程节点 ContractChain chain = new ContractChain(0,this.originalRequest,this.interceptorList); return chain.proceed(this.originalRequest); }

}

获取节点中的请求参数,实例化当前责任链节点(contractCompactInitImpl),在执行节点中的proceed方法来获取当前节点的参数以及获取节点的信息。

/**
 * @author xbhog
 * @describe: 合同节点
 * @date 2023/7/11
 */
@Slf4j
public class ContractChain implements Chain {
    private final Integer index;
private final T request;

private final List> interceptors;

public ContractChain(Integer index, T request, List> interceptors) { this.index = index; this.request = request; this.interceptors = interceptors; }

@Override public T request() { return this.request; }

@Override public ContractResponse proceed(T request) { //控制节点流程 if(this.index >= this.interceptors.size()){ throw new IllegalArgumentException("index越界"); } //下一个节点参数设置 Chain nextChain = new ContractChain(this.index + 1, request, this.interceptors); //获取节点信息 Interceptor interceptor = this.interceptors.get(this.index); Class extends Interceptor> aClass = interceptor.getClass(); log.info("当前节点:{}",aClass.getSimpleName()); ContractResponse response = interceptor.process(nextChain); if(Objects.isNull(response)){ throw new NullPointerException("intercetor"+interceptor+"return null"); } return response; }

}

 

到此合同签章的架构流程已经确定,后续只要填充Interceptor具体的实现类即可。
在代码中ContractResponse response = interceptor.process(nextChain);来执行合同初始化节点的具体操作。

/**
 * @author xbhog
 * @describe: 合同文本初始化
 * @date 2023/7/12
 */
@Slf4j
@Component
public class ContractSignCompactInitImpl implements Interceptor {
    public ContractSignCompactInitImpl() {
    }
@Override
public ContractResponse process(Chain chain) {
    log.info("=============执行合同文本初始化拦截器开始");
    //获取处理的请求参数
    T request = chain.request();
    request.setStatus("1");
    log.info("=============执行合同文本初始化拦截器结束");
    //进入下一个责任链节点
    ContractResponse response =  chain.proceed(request);
    if(Objects.isNull(response)){
        log.error("返回值的为空");
        response = ContractResponse.builder().status("fail").mas("处理失败").build();
    }
    //其他处理
    return response;
}

}

 

测试验证

@SpringBootTest
class SPringBootTestApplicationTests {
    @Autowired
    @Qualifier("contractSignProcessor")
    private Processor contractSignProcessor;
@Test
void contextLoads() {
    ContractRequest contractRequest = new ContractRequest();
    contractRequest.setName("xbhog");
    contractRequest.setAge("12");
    ContractResponse process = contractSignProcessor.process(contractRequest);
    System.out.println(process);
}

}

在这里只需要调用合同签章入口的方法即可进入合同签章的流程。

2023-07-16 13:25:13.063  INFO 26892 --- [           main] c.e.s.c.ContractSignProcessor            : 签章开始
2023-07-16 13:25:13.067  INFO 26892 --- [           main] c.e.s.chainresponsibility.ContractChain  : 当前节点:ContractSignCompactInitImpl
2023-07-16 13:25:13.068  INFO 26892 --- [           main] c.e.s.c.i.ContractSignCompactInitImpl    : =============执行合同文本初始化拦截器开始
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.i.ContractSignCompactInitImpl    : =============执行合同文本初始化拦截器结束
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.chainresponsibility.ContractChain  : 当前节点:ContractSignGenerateImpl
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignGenerateImpl    : =============执行合同文本生成拦截器开始
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignGenerateImpl    : =============执行合同文本生成拦截器结束
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.chainresponsibility.ContractChain  : 当前节点:ContractSignMockImpl
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignMockImpl        : =============执行签章挡板拦截器开始
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignMockImpl        : =============执行签章挡板拦截器结束
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.chainresponsibility.ContractChain  : 当前节点:ContractSignMqImpl
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignMqImpl          : =============执行合同签章完成发送mq拦截器开始
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.chainresponsibility.ContractChain  : 当前节点:ContractSignSerialImpl
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignSerialImpl      : =============执行合同签章流水处理拦截器开始
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.chainresponsibility.ContractChain  : 当前节点:ContractSignSaveUploadImpl
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignSaveUploadImpl  : =============执行合同签章完成上传服务器拦截器开始
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.chainresponsibility.ContractChain  : 当前节点:ContractSignTradeImpl
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignTradeImpl       : =============执行签章渠道实际调用拦截器开始
2023-07-16 13:25:13.069  INFO 26892 --- [           main] c.e.s.c.channel.ContractSignChannelImpl  : 签章处理开始
2023-07-16 13:25:13.070  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignSaveUploadImpl  : 开始上传服务器
2023-07-16 13:25:13.070  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignSaveUploadImpl  : .............
2023-07-16 13:25:13.070  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignSaveUploadImpl  : 上传服务器完成
2023-07-16 13:25:13.070  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignSaveUploadImpl  : =============执行合同签章完成上传服务器拦截器结束
2023-07-16 13:25:13.070  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignSerialImpl      : =============执行合同签章流水处理拦截器结束
2023-07-16 13:25:13.070  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignMqImpl          : 发送MQ给下游处理数据
2023-07-16 13:25:13.070  INFO 26892 --- [           main] c.e.s.c.impl.ContractSignMqImpl          : =============执行合同签章完成发送mq拦截器结束
ContractResponse(status=success, mas=处理成功)

策略+责任链+组合代码实现

以下是完整的合同签章入口实现类:

/**
 * @author xbhog
 * @describe: 责任链+组合实现合同签章
 * @date 2023/7/11
 */
@Slf4j
@Component
public class ContractSignProcessor  implements Processor {
@Resource(name = "contractSignCompactInitImpl")
private Interceptor contractCompactInitImpl;

@Resource(name = "contractSignGenerateImpl") private Interceptor contractGenerateImpl;

@Resource(name = "contractSignMockImpl") private Interceptor contractSignMockImpl;

@Resource(name = "contractSignMqImpl") private Interceptor contractSignMqImpl;

@Resource(name = "contractSignSaveUploadImpl") private Interceptor contractSignSaveUploadImpl;

@Resource(name = "contractSignSerialImpl") private Interceptor contractSignSerialImpl;

@Resource(name = "contractSignTradeImpl") private Interceptor ContractSignTradeImpl;

public ContractSignProcessor() { }

@Override public ContractResponse process(T paramter) { //获取所有的监听器 List> interceptorList = new ArrayList(); interceptorList.add(contractCompactInitImpl); interceptorList.add(contractGenerateImpl); interceptorList.add(contractSignMockImpl); interceptorList.add(contractSignMqImpl); interceptorList.add(contractSignSerialImpl); interceptorList.add(contractSignSaveUploadImpl); interceptorList.add(ContractSignTradeImpl); //开始签章 log.info("签章开始"); return new ContractCall(paramter,interceptorList).exectue(); }

}

 

可以看到,目前的合同签章的处理流程需要的节点数已经7个了,后续如果新增节点或者减少节点都需要对该类进行手动的处理;比如:减少一个节点的流程。

  1. 删除节点实现的注入
  2. 删除list中的bean实现类

为方便后续的拓展(懒是社会进步的加速器,不是),在责任链,组合的基础上通过策略模式来修改bean的注入方式。
完整的项目结构和项目类图就是作者文章开始放的,可返回查看。
在第一部分的基础上增加的功能点如下

  1. 新增签章注解
  2. 新增签章节点枚举
  3. 新增签章配置类

签章注解实现

package com.example.springboottest.chainresponsibility.annotations;

import com.example.springboottest.chainresponsibility.Enum.ContractSignEnum;

 

import java.lang.annotation.*;

 

/**

 

    • @author xbhog

 

    • @describe:

 

    • @date 2023/7/15 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ContractSign { ContractSignEnum.SignChannel SIGN_CHANNEL();

 

 

}

设置注解修饰对象的范围,主要是对bean的一个注入,所以类型选择type,

  • TYPE: 用于描述类、接口(包括注解类型) 或enum声明

设置注解的运行周期(有效范围),一般是运行时有效,

  • RUNTIME:在运行时有效(大部分注解的选择)

设置该注解的数据类型,

  • ENUM:枚举类型,方便统一处理

枚举实现

package com.xbhog.chainresponsibility.Enum;

/**

 

    • @author xbhog

 

    • @describe:

 

  • @date 2023/7/15 */ public class ContractSignEnum { public enum SignChannel {
     SIGN_INIT(1, "合同文本初始化"),
     SIGN_GENERATE(2, "合同文本生成"),
     SIGN_MOCK(3, "签章挡板"),
     SIGN_MQ(4, "合同签章完成发送MQ"),
     SIGN_TABLE(5, "合同签章表处理"),
     SIGN_UPLOAD(6, "合同签章完成上传服务器"),
     SIGN_TRADE(7, "签章渠道实际调用");
    

    private Integer code; private String info;

    SignChannel(Integer code, String info) { this.code = code; this.info = info; } ......

    }
    }

 

对合同签章中的流程节点进行统一的配置。

签章配置类

在项目启动的时候,通过注解工具类AnnotationUtils扫描所有被ContractSign注解修饰的类,将这些类通过Map进行存储,方便后续的调用。

public class SignConfig {
    @Resource
    protected List contractSignList;
protected static final Map CONTRACT_SIGN_MAP = new ConcurrentHashMap();

@PostConstruct public void init(){ contractSignList.forEach(interceptor -> { //查找这个接口的实现类上有没有ContractSign注解 ContractSign sign = AnnotationUtils.findAnnotation(interceptor.getClass(), ContractSign.class); if(!Objects.isNull(sign)){ CONTRACT_SIGN_MAP.put(sign.SIGN_CHANNEL().getCode(),interceptor); } }); }

}

到此,简化了Bean的注入方式。

签章注解使用

以合同文本初始化ContractSignCompactInitImpl来说。

/**
 * @author xbhog
 * @describe: 合同文本初始化
 * @date 2023/7/12
 */
@Slf4j
@ContractSign(SIGN_CHANNEL = ContractSignEnum.SignChannel.SIGN_INIT)
@Component
public class ContractSignCompactInitImpl implements Interceptor {
    public ContractSignCompactInitImpl() {
    }
@Override
public ContractResponse process(Chain chain) {
    log.info("=============执行合同文本初始化拦截器开始");
    //获取处理的请求参数
    T request = chain.request();
    request.setStatus("1");
    log.info("=============执行合同文本初始化拦截器结束");
    //进入下一个责任链节点
    ContractResponse response =  chain.proceed(request);
    if(Objects.isNull(response)){
        log.error("返回值的为空");
        response = ContractResponse.builder().status("fail").mas("处理失败").build();
    }
    //其他处理
    return response;
}

}

在该实现类上绑定了枚举@ContractSign(SIGN_CHANNEL = ContractSignEnum.SignChannel.SIGN_INIT).
在合同签章入口类(ContractSignProcessor)中的变更如下:

@Slf4j
@Component
public class ContractSignProcessor  extends SignConfig implements Processor {
public ContractSignProcessor() {
}

@Override public ContractResponse process(T paramter) { //获取所有的监听器 List> interceptorList = new ArrayList(); //获取排序后的结果,保证责任链的顺序,hashmap中key如果是数字的话,通过hashcode编码后是有序的 for(Integer key : CONTRACT_SIGN_MAP.keySet()){ interceptorList.add(CONTRACT_SIGN_MAP.get(key)); } //开始签章 log.info("签章开始"); return new ContractCall(paramter,interceptorList).exectue(); }

}

通过继承合同签章配置类(SignConfig),来获取Map,遍历Map添加到list后进入责任链流程。
到此,整个策略+责任链+组合的优化方式结束了。


问题:
责任链中的顺序是怎么保证的?
相信认真看完的你能在文章或者代码中找到答案。

本文(https://verysu.com)仅供学习!所有权归属原作者。侵删!文章来源:作者 https://www.cnblogs.com/xbhog/p/17559095.html

 

更多文章:

  1. 设计模式在外卖营销业务中的实践
  2. RocketMQ消息回溯实践与解析
  3. 浅析设计模式5 -- 责任链模式
  4. 殷浩详解DDD 第四讲:领域层设计规范
  5. Eureka源码剖析之一:初始化-启动
  6. 责任链模式在复杂数据处理场景中的实战
  7. Eureka源码剖析之三:服务拉取
  8. 事务异常:Transaction rolled back because it has been marked as rollback-only
  9. 手把手教你实战TDD
  10. 殷浩详解DDD系列 第二讲 - 应用架构
标签: 组合 转载 Java 系统设计 策略模式 设计模式 责任链模式 合同
最后更新:2024-11-03

秋天0261

关注Java领域,后端开发、Netty、Zookeeper、Kafka、ES、分布式、微服务、架构等。分享技术干货,架构设计,实战经验等。

打赏 点赞
< 上一篇
下一篇 >
广告
文章目录
  • 前置内容
  • 签章的处理流程
  • 流程实现
    • 项目结构
    • 项目类图
    • 责任链+组合模式代码实现
      • 工程结构
      • 责任链中的对象定义
      • 责任链处理流程
      • 测试验证
    • 策略+责任链+组合代码实现
      • 签章注解实现
      • 枚举实现
      • 签章配置类
      • 签章注解使用
最新 热点 推荐
最新 热点 推荐
视频笔记:微服务架构P4 设计模式:每服务数据库、API 网关和事件驱动架构 干货 | 论Elasticsearch数据建模的重要性 马蜂窝消息总线——面向业务的消息服务设计 基于 MySQL Binlog 实现可配置的异构数据同步 视频笔记:Google发布Agent2Agent协议 视频笔记:什么是微服务,为什么是微服务? 视频笔记:什么是AI 智能体? 视频笔记:什么是Flink?
Elasticsearch 使用误区之六——富文本内容写入前不清洗基于 MySQL Binlog 实现可配置的异构数据同步马蜂窝消息总线——面向业务的消息服务设计视频笔记:微服务架构P4 设计模式:每服务数据库、API 网关和事件驱动架构干货 | 论Elasticsearch数据建模的重要性你可以不用RxJava,但必须得领悟它的思想!如何秒级实现接口间“幂等”补偿:一款轻量级仿幂等数据校正处理辅助工具视频笔记:什么是Flink?
FSM-COLA无状态状态机 MySQL8.0驱动升级事故——之三 Prompt之【翻译】 ChatGPT的探索与实践 系统设计 | 如何管理应用系统中的配置? 《2023 年度 AI 大事记》 记一次堆内外内存问题的排查和优化 MySQL性能优化浅析及线上案例讲解

CRUD (1) Event Sourcing (1) graphql (1) id (1) NoSQL (1) quarkus (1) rest (1) RocketMQ (2) Spring Boot (1) zk (1) zookeeper (1) 上下文 (1) 事务消息 (1) 二级缓存 (1) 值对象 (1) 关系数据库 (1) 分布式缓存 (1) 原子性 (1) 唯一ID (1) 商品 (1) 多对多 (1) 子域 (1) 字符集 (1) 客户端心跳 (1) 幂等 (2) 干货 (1) 并发 (1) 应用场景 (1) 应用架构图 (1) 康威定律 (2) 异步复制 (1) 微服务架构 (3) 总体方案 (1) 技术方案 (2) 技术架构 (2) 技术架构图 (1) 技能 (1) 持续集成 (1) 支撑域 (1) 故障恢复 (1) 数据架构图 (1) 方案选型 (1) 日记 (1) 服务发现 (1) 服务治理 (1) 服务注册 (2) 机房 (1) 核心域 (1) 泄漏 (1) 洋葱架构 (1) 消息队列 (5) 源码剖析 (1) 灰度发布 (1) 熔断 (1) 生态 (1) 画图工具 (1) 研发团队 (1) 线程 (2) 组织架构 (1) 缓存架构 (1) 编码 (1) 视频 (19) 读写分离 (1) 贵州 (1) 软件设计 (1) 迁移 (1) 通用域 (1) 集群化 (1) 雪花算法 (1) 顺序消息 (1)

推荐链接🔗
  • AI工具集
  • 工具箱🛠️

站点已运行 1470 天

COPYRIGHT © 2014-2025 verysu.com . ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2

x

通知