N

Norlcayn的博客

A text-focused Halo theme

  • 首页
  • 文章
  • 默认分类
  • 关于
主页 策略模式
文章

策略模式

发表于 2026-01-16 更新于 昨天
作者 Administrator
13~17 分钟 阅读

问题说明

当前项目中,订单的状态比较多,不同状态下取消订单的逻辑是不同的;而且用户不同,可操作的内容也不同

  • 普通用户:可取消待支付、派单中、待服务的订单
  • 运营人员:可取消派单中、待服务、服务中、完成的订单

whiteboard_exported_image (3)

因此最终实现取消订单的代码逻辑如下所示:

public void cancel(OrderCancelDTO orderCancelDTO) {

    Orders orders = getById(orderCancelDTO.getId());//查询订单信息
    Integer ordersStatus = orders.getOrdersStatus();//订单状态
    CurrentUserInfo currentUserInfo = UserContext.currentUser();//获取当前用户
    Integer userType = currentUserInfo.getUserType();//用户类型

    if(UserType.C_USER==userType){//普通用户取消订单
        if(OrderStatusEnum.NO_PAY.getStatus()==ordersStatus){ //订单状态为待支付
            //...
        }else if(OrderStatusEnum.DISPATCHING.getStatus()==ordersStatus){ //订单状态为派单中
            //...
        }else if(OrderStatusEnum.NO_SERVE.getStatus()==ordersStatus){ //订单状态为待服务
            //...
        }else{
            throw new CommonException("当前订单状态不支持取消");
        }
    }else if(UserType.OPERATION==userType){//运营人员取消订单
        if(OrderStatusEnum.DISPATCHING.getStatus()==ordersStatus) { //订单状态为派单中
            //...
        }else if(OrderStatusEnum.NO_SERVE.getStatus()==ordersStatus){//订单状态为待服务
            //...
        }else if(OrderStatusEnum.SERVING.getStatus()==ordersStatus){//订单状态为服务中
            //...
        }else if(OrderStatusEnum.FINISHED.getStatus()==ordersStatus){//订单状态为已完成
            //...
        }else{
            throw new CommonException("当前订单状态不支持取消");
        }
    }
}

这种代码虽然可以实现功能,但是可读性和扩展性都很差,我们可以使用策略模式进行改造

策略模式

使用场景:针对一个业务,有多个不同的执行分支,需要根据不同的条件,切换到不同的分支上去

好处:解决使用条件语句(如if…else)导致的复杂性和扩展性问题

策略模式需要开发下面的接口和类:

  • 策略接口:定义策略方法
  • 策略实现类:需要实现策略接口,并重写接口中声明的策略方法
  • 上下文环境类:需要维护所有策略对象,然后根据不同的条件,调用不同的策略对象

9c5aff57-8b8e-4dbf-b596-26bc6114310a

下面以一个**支付方式**选择的场景为例子来讲解一下,需求如下:

  1. 当前项目支持微信和阿里两种支付方式
  2. 用户可以自行选择一种支付方式
  3. 根据用户选择,执行对应的支付代码

1)定义策略接口

创建PayStrategy接口

package com.jzo2o.orders.manager.service.strategy;

/**
 * 支付策略接口
 */
public interface PayStrategy {

    //策略方法
    void pay();
}

2)定义微信支付策略类

package com.jzo2o.orders.manager.service.strategy.impl;

import com.jzo2o.orders.manager.service.strategy.PayStrategy;
import org.springframework.stereotype.Component;

/**
 * 微信支付策略实现类
 */
@Component("wxPay")
public class WxPayStrategy implements PayStrategy {
    @Override
    public void pay() {
        System.out.println("使用微信进行支付");
    }
}

3)定义阿里支付策略类

package com.jzo2o.orders.manager.service.strategy.impl;

import com.jzo2o.orders.manager.service.strategy.PayStrategy;
import org.springframework.stereotype.Component;

/**
 * 阿里支付策略实现类
 */
@Component("aliPay")
public class AliPayStrategy implements PayStrategy {
    @Override
    public void pay() {
        System.out.println("使用阿里进行支付");
    }
}

4)定义上下文环境类

package com.jzo2o.orders.manager.service.strategy;

import cn.hutool.extra.spring.SpringUtil;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;

/**
 * 上下文环境类(策略管理类)
 */
@Component
public class PayStrategyManager {
    Map<String, PayStrategy> payStrategyMap;

    //维护所有策略对象
    @PostConstruct //此注解标注的方法会在当前对象PayStrategyManager创建之后自动执行
    public void init() {
        //key: 当前对象在容器中的id
        //value: 当前对象
        payStrategyMap = SpringUtil.getBeansOfType(PayStrategy.class);
    }

    //根据用户需求, 执行指定的策略对象
    public void pay(String key) {
        PayStrategy payStrategy = payStrategyMap.get(key);
        if (payStrategy == null) {
            throw new RuntimeException("暂不支持当前支付方式");
        }
        payStrategy.pay();
    }
}

5)测试类

package com.jzo2o.orders.manager.service.strategy;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * 测试支付方式的选择
 */
@SpringBootTest
public class PayTest {

    @Autowired
    private PayStrategyManager payStrategyManager;

    @Test
    public void test(){
        //测试微信支付
        payStrategyManager.pay("wxPay");
        //测试阿里支付
        payStrategyManager.pay("aliPay");
    }
}
云岚到家相关技术栈
设计模式 策略模式
许可协议:  CC BY 4.0
分享

相关文章

1月 16, 2026

状态机

什么是状态机 需求说明 在订单模块中订单共设计了7种状态,如下图 订单会在多个状态间进行转换,这就需要开发人员都去记忆这些转换关系,这是非常麻烦的 if(订单状态 == 待支付){ //如果用户支付成功,执行此场景下的业务逻辑,更新订单状态为派单中 update(id,派单中) ) if(

1月 16, 2026

数据表设计规范

设计范式 数据库设计三范式: 第一范式:数据表中的每一列都是原子的,不可再拆分 第二范式:每张表中的一条记录只描述一个实体 第三范式:数据表中不要存在冗余字段(可以通过其他字段推导出的字段) 1)第一范式:数据表中的每一列都是原子的,不可再拆分 有一张用户考勤表设计如下 id 用户名 考勤时间 1

1月 16, 2026

缓存优化

针对系统中访问频率很高的页面,常见的优化方案如下: 将页面做页面静态化处理 如果静态化之后依旧无法满足需求,可以将静态资源转移到CDN服务器 页面上变动的内容可以异步请求后端服务器获取数据,后端可以添加缓存来减轻数据库的压力 数据库方面可以通过合理的存储引擎选择、表字段设计、索引设计等进一步提高查询

下一篇

超卖方案(线程锁)

上一篇

EasyExcel(报表导出)

最近更新

  • Hello Halo
  • 状态机
  • 数据表设计规范
  • 缓存优化
  • 事务失效

热门标签

Halo 异常处理 Redisson 并行 Vue 并发 递归 请求限流 SpringAMQP 类加载器

目录

©2026 Norlcayn的博客. 保留部分权利。

使用 Halo 主题 Chirpy