Spring小技巧之设计模式

Spring小技巧之设计模式

责任链模式

模式定义

  • 该模式在《图解设计模式》的第14章节《Chain of Responsibility模式》有详细的介绍。简单来说:当一个对象需要交给多个处理类依次处理的时候就可以用责任链模式,Servlet Filter、Spring 拦截器链都是这一模式的实际应用,在订单履约等业务场景中也经常使用到。

示例代码

  • OrderCreatedBaseHandler:责任链顶层接口定义类,所有处理器都实现该接口。

    java 复制代码
    package com.wwq.test;
    
    /**
     * 创建订单责任链接口
     */
    public interface OrderCreatedBaseHandler {
    
        /**
         * 运行消息处理
         */
        void run(Order order);
    
        /**
         * 是否执行</br>
         * 子类重写该方法,可根据配置开关,来确定是否执行 run 方法
         */
        default boolean isRun(Order order){
            return true;
        }
    
    }
  • OrderCreatedOperate:责任链执行器类,是整个责任链的管理容器和启动入口。利用Spring批量注入接口实现类为List的机制串联整个链条。

    java 复制代码
    package com.wwq.test;
    
    /**
     * 责任链执行器,运行所有 OrderCreatedBaseHandler 实现类
     */
    @Component
    public class OrderCreatedOperate {
    
        /*
         * 注入全部处理器
         */
        @Autowired
        private List<OrderCreatedBaseHandler>  baseOrderCreatedHandles;
    
        /**
         * 运行消息处理
         * @param orderCreatedMessage 订单创建消息
         */
        public void run(Order order) {
            for(OrderCreatedBaseHandler handler : baseOrderCreatedHandles){
               if(handler.isRun(order)){
                   handler.run(order);
               }
            }
        }
        
    }
  • 各个责任链处理,可通过@Order注解调整他们的执行顺序。

    java 复制代码
    package com.wwq.test;
    
    /**
     * 创建订单处理器
     */
    @Slf4j
    @Component
    public class OrderCreatedHandler implements OrderCreatedBaseHandler {
    
        public void run(OrderCreatedMessage orderCreatedMessage){
            // TODO 创建订单
        }
        
    }
    java 复制代码
    package com.wwq.test;
    
    /**
     * 积分处理器
     */
    @Slf4j
    @Component
    public class PointHandler implements OrderCreatedBaseHandler {
    
        public void run(OrderCreatedMessage orderCreatedMessage){
            // TODO 积分抵扣和发送
        }
        
    }
    java 复制代码
    package com.wwq.test;
    
    /**
     * 物流处理器
     */
    @Slf4j
    @Component
    public class LogisticsHandler implements OrderCreatedBaseHandler {
    
        public void run(OrderCreatedMessage orderCreatedMessage){
            // TODO 处理物流流程信息
        }
        
    }
    java 复制代码
    package com.wwq.test;
    
    /**
     * 商品库存处理器
     */
    @Slf4j
    @Component
    public class StockHandler implements OrderCreatedBaseHandler {
    
        public void run(OrderCreatedMessage orderCreatedMessage){
            // TODO 库存扣减
        }
        
    }
  • 如果想各个处理器并行执行,可以使用 CompletableFuture.runAsync() 提交异步任务。

    java 复制代码
    package com.wwq.test;
    
    /**
     * 责任链执行器,运行所有 OrderCreatedBaseHandler 实现类
     */
    @Component
    public class OrderCreatedOperate {
    
        /*
         * 责任链执行线程池
         */
        @Autowired
        @Qualifier("orderCreatedTaskExecutor")
        private Executor orderCreatedTaskExecutor;
    
        /*
         * 注入全部处理器
         */
        @Autowired
        private List<OrderCreatedBaseHandler>  baseOrderCreatedHandles;
    
        /**
         * 运行消息处理
         * @param orderCreatedMessage 订单创建消息
         */
        public void run(Order order) {
    
            /*
             * 收集 Future
             */
            List<CompletableFuture<?>> futures = new ArrayList<>();
    
            /*
             * 异步执行每个处理器
             */
            for(OrderCreatedBaseHandler handler : baseOrderCreatedHandles){
                futures.add(CompletableFuture.runAsync(() -> {
                    if(handler.isRun(order)){
                        handler.run(order);
                    }
                }, orderCreatedTaskExecutor));
            }
    
            /*
             * 等待所有异步任务全部执行完毕
             */
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        }
    
    }

策略模式模式

模式定义

  • 该模式在《图解设计模式》的第10章节《Strategy模式》有详细的介绍。当需要根据某种条件整体替换运算逻辑时就可以使用策略模式,在支付渠道、文件解析、报表导出、优惠计算等场景都有应用。

示例代码

  • 策略接口定义

    java 复制代码
    	public interface PayStrategy {
    	    // 渠道标识
    	    String getChannel();
    	    // 支付逻辑
    	    void pay(BigDecimal amount);
    	}
  • 策略实现

    java 复制代码
    @Component
    public class AliPayStrategy implements PayStrategy {
        @Override
        public String getChannel() {
            return "ALI";
        }
        @Override
        public void pay(BigDecimal amount) {
            System.out.println("支付宝支付:" + amount);
        }
    }
    java 复制代码
    @Component
    public class WxPayStrategy implements PayStrategy {
        @Override
        public String getChannel() {
            return "WX";
        }
        @Override
        public void pay(BigDecimal amount) {
            System.out.println("微信支付:" + amount);
        }
    }
  • 策略工厂

    java 复制代码
    @Service
    public class PayStrategyFactory {
        // 自动注入全部策略实现
        private final Map<String, PayStrategy> strategyMap;
    
        @Autowired
        public PayStrategyFactory(List<PayStrategy> payStrategies) {
            this.strategyMap = new HashMap<>();
            for(PayStrategy strategy : payStrategies){
                strategyMap.put(strategy.getChannel(), strategy);
            }
        }
    
        // 根据渠道获取对应策略
        public PayStrategy getStrategy(Integer channel) {
            return strategyMap.get(channel);
        }
    }
  • 使用策略

    java 复制代码
    @Autowired
    private PayStrategyFactory factory;
    
    public void test() {
        PayStrategy ali = factory.getStrategy("ALI");
        ali.pay(new BigDecimal("100"));
    }
相关推荐
露天赏雪2 小时前
第3篇:Sentinel熔断降级实战:大模型接口抖动时的服务兜底方案
java·开发语言·人工智能·spring boot·spring·servlet·sentinel
captain3762 小时前
▲统一功能——DispatcherServlet源码分析
java·spring·java-ee·log4j·maven
骑着蜗牛撵大象3274 小时前
MySQL 8.0 迁移后 SQL 变慢:执行计划里 3 类被忽略的成本差异
android·数据库·sql·mysql·优化器·执行计划
zhengfei6116 小时前
Go-fastdfs /reload 未授权访问: 有效PoC
数据库·sql
大维8 小时前
DBX 实测:从 SQLite 查询到 MiniMax-M3 自然语言生成 SQL
数据库·sql·sqlite
是2的10次方啊9 小时前
设计模式与生活⑭:一栋楼,共用一份热
设计模式
景煜拾年10 小时前
InnoAI SQL 助手
运维·数据库·笔记·sql
TeamDev11 小时前
使用 JxBrowser 在桌面应用中集成 Spring
java·前端·后端·spring·混合应用·jxbrowser·浏览器控件
SL_staff1 天前
从配置失效到逻辑复用:JVS-Logic 如何构建可治理的业务编排中枢
java·spring·产品
程序员吕洞宾1 天前
开源多维表格SmartTable v1.6.10 —— 用户名登录、数据评论及@人、表单分享二维码、性能优化、部署及升级优化
spring·性能优化·开源