怎么利用策略模式与简单工厂模式实现业务算路逻辑的高度解耦与横向扩展

陌墨君_8089

陌墨君_8089

2026-04-14

140人浏览

原创

策略模式管“怎么算”,简单工厂模式管“用哪个算”,二者组合实现开闭原则:新增优惠规则只需加两个类、改一处注册逻辑,不触碰原有业务代码。

怎么利用策略模式与简单工厂模式实现业务算路逻辑的高度解耦与横向扩展

直接说结论:策略模式管「怎么算」,简单工厂模式管「用哪个算」,两者组合后,新增一种优惠规则,只需加两个类、改一处注册逻辑,不用碰原有任何业务代码。

为什么不能只用 if-else 或只用策略模式

if-else 写死在方法里,每次加新会员等级或新活动规则,都得打开 actualPay 方法改逻辑,一不小心就破坏已有分支;只上策略模式但没工厂,客户端就得自己 new 具体策略类(比如 new SeniorMemberStrategy()),等于把创建逻辑散落在各处,后续想统一加日志、缓存或参数校验时无从下手。

常见错误现象包括:

  • 新增一个「钻石会员」后,忘记在某个支付入口的 if 分支里补 case,导致该入口始终按非会员结算
  • 策略类构造依赖了 RedisTemplate,但上下文手动 new 时没传,运行时报 NullPointerException
  • 不同模块(订单、退款、对账)各自 new 同一类策略,导致配置不一致,比如折扣率一个写 0.6,一个写 0.599

策略接口定义要聚焦行为契约,而非数据结构

接口名别叫 MemberDiscountStrategy 这种带具体业务词的,容易锁死场景。更通用的命名是 CalculationStrategy,方法签名只暴露必要参数:

public interface CalculationStrategy {
    BigDecimal calculate(BigDecimal baseAmount, Map<string object> context);
}</string>

这样未来扩展「满减」「跨店叠加」「积分抵扣」等新算路时,不用改接口,只新增实现类即可。关键点:

  • baseAmount 是原始金额,不预设是否含税、是否已折上折,由调用方决定传什么
  • context 用 Map 而非 DTO,避免每加一个字段就改接口——策略内部只取自己关心的 key,比如 context.get("memberLevel") 或 context.get("orderTotal")
  • 返回值用 BigDecimal,不返回「减免额」也不返回「实付额」,由上下文决定怎么用结果

简单工厂必须控制实例生命周期,不能每次都 new

工厂类里别写 return new JuniorMemberStrategy() 这种裸 new,而应提前初始化好单例对象:

剪映
剪映

一款AI视频创作工具,主要用于一款全能易用的桌面端剪辑软件,适合需要提升相关任务效率的用户。

下载
public class CalculationStrategyFactory {
    private static final Map<string calculationstrategy> STRATEGY_MAP = new ConcurrentHashMap();

    static {
        STRATEGY_MAP.put("JUNIOR", new JuniorMemberStrategy());
        STRATEGY_MAP.put("SENIOR", new SeniorMemberStrategy());
        STRATEGY_MAP.put("FLASH_SALE", new FlashSaleStrategy());
    }

    public static CalculationStrategy getStrategy(String code) {
        CalculationStrategy strategy = STRATEGY_MAP.get(code);
        if (strategy == null) {
            throw new IllegalArgumentException("No strategy found for code: " + code);
        }
        return strategy;
    }
}</string>

这么做的原因:

  • 避免重复构造开销,尤其策略里含连接池、缓存 client 时
  • 方便后续统一做 AOP,比如所有策略执行前记录耗时、失败自动降级
  • 防止误传空字符串或大小写不一致导致 getStrategy(null) 报 NPE,工厂层主动兜底

注意:如果策略需要运行时动态加载(如从 DB 配置表读规则),那就不能用静态 map,得换成 Spring 的 @Scope("prototype") + ObjectProvider 拉取,但那是另一层复杂度了。

上下文类要隔离策略选择与策略执行

别让业务代码直接调工厂拿策略再调方法,中间必须包一层 CalculationContext:

public class CalculationContext {
    private CalculationStrategy strategy;

    public void setStrategy(CalculationStrategy strategy) {
        this.strategy = strategy;
    }

    public BigDecimal execute(BigDecimal amount, Map<string object> context) {
        if (strategy == null) {
            throw new IllegalStateException("Strategy not set");
        }
        return strategy.calculate(amount, context);
    }
}</string>

这样做的实际好处:

  • 测试时可轻松 mock 策略行为,不用启动整个 Spring 容器
  • 后续加「策略链」(比如先打折再满减)只要改 execute 方法,不侵入已有策略类
  • 前端传错 memberLevel=senior(小写),可以在 setStrategy 里统一转大写或抛明确异常,而不是让策略类自己处理脏数据

真正容易被忽略的是:策略类内部永远不要尝试从 Spring 上下文里 getBean,那会制造隐式依赖,导致单元测试无法脱离容器运行。所有外部依赖(如 Redis、配置中心)必须通过构造函数注入,由工厂类统一组装。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

9497

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

6642

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

5912

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1044

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

868

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1236

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2489

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

19831

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1135

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习