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"));
    }
相关推荐
小小龙学IT22 分钟前
Qt 数据库编程(Qt SQL 模块)深度解析
数据库·sql·qt
疯狂打码的少年1 小时前
【数据库技术】SQL概述与数据定义(DDL:CREATE/DROP/ALTER)
数据库·笔记·sql·oracle
Supersist2 小时前
【Spring】 BeanFactory 和 ApplicationContext 体系结构
后端·spring
码匠许师傅3 小时前
【设计模式精讲】7.建造者模式(Builder)
设计模式·建造者模式
Sam_Deep_Thinking3 小时前
聊聊开闭原则,以及它在Spring里的样子
java·后端·spring·程序员·开闭原则
Blockchina3 小时前
Codex安全盲区:我用4组本地测试复盘SQLi、XSS、越权与路径穿越
sql·安全·xss
码匠许师傅3 小时前
【设计模式精讲】6.抽象工厂(Abstract Factory)
c++·设计模式
SQL-First布道者4 小时前
⚡ Spring JDBC 完整体系 · 第 5 讲 · Spring Boot Starter JDBC
java·spring boot·spring·mybatis·spring jdbc
木井巳4 小时前
【JavaEE】Spring Web MVC 入门
java·spring boot·spring·servlet·java-ee
2601_9619017014 小时前
SpringBoot使用Nacos进行application.yml配置管理
java·spring boot·spring