【设计模型】策略模式

文章目录


前言

 策略模式,就是把同一件事的不同做法分别封装起来,使用时选择其中一种。


电商场景中的例子

以电商中下单时计算优惠后的应付金额为例。假设一个订单每次只能选择一种优惠

  • 优惠方式有:满 300 减 50、满 200 减 30、打九折...
  • 订单原价都是400
  • 得到的应付金额为:350、370、360...

假设商品价格和优惠使用资格已经由服务端确认。先定义一个统一接口,规定所有优惠策略都必须能根据原价计算应付金额:

java 复制代码
public interface DiscountStrategy {
    BigDecimal calculatePayAmount(BigDecimal originalAmount);
}

这个接口只规定需要做什么,具体怎么算,由实现类决定。金额使用 BigDecimal,避免直接使用 double 带来的二进制浮点精度问题。

接着,把两种优惠规则分别写成两个类。

java 复制代码
// 策略一:满 300 减 50
public class FullReductionStrategy implements DiscountStrategy {

    @Override
    public BigDecimal calculatePayAmount(BigDecimal originalAmount) {
        BigDecimal threshold = new BigDecimal("300");
        BigDecimal reduction = new BigDecimal("50");

        // compareTo 返回值 >= 0,表示原价 >= 300
        if (originalAmount.compareTo(threshold) >= 0) {
        //执行减法
            return originalAmount.subtract(reduction);
        }

        // 不满足门槛,按原价支付
        return originalAmount;
    }
}

BigDecimal:double 使用二进制浮点数表示数值,无法精确表示某些十进制小数,因此计算结果可能出现微小误差。

传入 400,返回 350;传入 200,返回 200。满减门槛、减多少钱,都由这个策略负责。

java 复制代码
// 策略二:打九折
public class PercentageDiscountStrategy implements DiscountStrategy {

    @Override
    public BigDecimal calculatePayAmount(BigDecimal originalAmount) {
        return originalAmount
                .multiply(new BigDecimal("0.9"))
                .setScale(2, RoundingMode.HALF_UP);
    }
}

传入 400,返回 360.00。setScale(2, RoundingMode.HALF_UP) 表示按照这个示例约定,保留两位小数、四舍五入。

然后,订单服务通过统一接口调用优惠策略:

java 复制代码
public class OrderService {

    public BigDecimal calculateOrderAmount(
            BigDecimal originalAmount,
            DiscountStrategy strategy) {

        // 订单服务把优惠计算交给传入的策略
        BigDecimal payAmount =
                strategy.calculatePayAmount(originalAmount);

        // 后续可以使用 payAmount 保存订单等
        return payAmount;
    }
}

注意方法参数:

DiscountStrategy strategy

它声明的是接口类型,因此既能接收满减策略,也能接收折扣策略。这体现了 Java 的多态:调用相同的方法,实际执行哪个实现,取决于传入的对象。

实际调用时:

java 复制代码
OrderService orderService = new OrderService();
BigDecimal originalAmount = new BigDecimal("400.00");

// 选择满减策略
BigDecimal amount1 = orderService.calculateOrderAmount(
        originalAmount,
        new FullReductionStrategy()
);
System.out.println(amount1); // 350.00

// 选择九折策略
BigDecimal amount2 = orderService.calculateOrderAmount(
        originalAmount,
        new PercentageDiscountStrategy()
);
System.out.println(amount2); // 360.00

可以把这几部分对应起来看:

代码 在策略模式中的角色 负责什么
DiscountStrategy 策略接口 统一优惠计算方法
FullReductionStrategy 具体策略 实现满减规则
PercentageDiscountStrategy 具体策略 实现折扣规则
OrderService 上下文,即使用策略的业务类 调用策略,完成订单金额计算

实际项目中,怎么根据用户选择找到策略?

例如,可以维护"优惠类型 → 策略对象"的映射:

java 复制代码
Map<String, DiscountStrategy> strategies = Map.of(
        "FULL_REDUCTION", new FullReductionStrategy(),
        "PERCENTAGE_DISCOUNT", new PercentageDiscountStrategy()
);

// 假设服务端校验后,确定本次使用满减优惠
String promotionType = "FULL_REDUCTION";

// 根据类型找到策略对象
DiscountStrategy strategy = strategies.get(promotionType);

if (strategy == null) {
    throw new IllegalArgumentException("不支持的优惠类型");
}

// 统一执行
BigDecimal payAmount =
        orderService.calculateOrderAmount(originalAmount, strategy);

这里,Map 负责找到哪个策略,策略对象负责执行具体算法。策略模式本身并不要求必须使用 Map,简单的选择逻辑也可以。

策略模式的优势

其优势主要体现在后续修改需求时:

  • 增加优惠更方便。 新增"会员打八折",可以增加 MemberDiscountStrategy 并注册到映射中,订单服务的调用逻辑不用改。
  • 修改规则更集中。 满减要改成"满 500 减 80",主要修改满减策略,不需要进入订单服务调整一大段优惠分支。
  • 测试更独立。 可以单独测试满减策略在 299、300、301 元时是否计算正确,不必运行整个下单流程。
相关推荐
yuniko-n1 小时前
【Java】字符串相关坑点
java·开发语言·python
Terra.K1 小时前
Spring AI day1(SSE+AI)
java·人工智能·spring·springai
斑鸠喳喳1 小时前
线程本地存储 ThreadLocal
java·后端
Wang's Blog2 小时前
Java框架 SpringCloud 快速入门: 服务拆分案例 Demo
java·开发语言·spring cloud
DongQiShanRen2 小时前
裁决台账双向互校(上):名册与实物的第一道对账
java·linux·运维·数据库·人工智能·自然语言处理·数据挖掘
cpolar技术支持3 小时前
Spring Boot 接口本地正常,异地前端却报跨域?用 cpolar 跑通 CORS 预检与白名单
java·springboot·cpolar·前后端分离·cors
wuminyu3 小时前
Virtual Thread重投递至ForkJoinPool任务队列过程解析
java·linux·c语言·jvm·c++
小蒜学长3 小时前
在线保险服务与管理平台的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端·服务平台·在线保险
掉进电商坑三年没爬出来的东叔3 小时前
青龙面板进阶:一个面板聚合多平台签到,所有积分自动领
java·开发语言
殷色玫瑰4 小时前
C++ STL:stack、queue、priority_queue 与容器适配器详解
java·开发语言·数据结构·c++·算法·visualstudio