当前位置: 首页 > news >正文

策略模式与工厂模式的黄金组合:从设计到实战

策略模式和工厂模式是软件开发中最常用的两种设计模式,当它们结合使用时,能产生1+1>2的效果。本文将通过实际案例,阐述这两种模式的协同应用,让代码架构更优雅、可维护性更强。

一、为什么需要组合使用?

单独使用的痛点
  • 策略模式:客户端需要知道所有策略类,并手动创建策略实例
  • 工厂模式:单独使用时主要解决对象创建问题,不涉及算法切换
组合后的优势
  1. 彻底解耦:客户端无需知道策略类的存在和创建方式
  2. 一键切换:通过工厂统一管理策略实例,实现算法动态切换
  3. 集中管理:策略的注册、创建、缓存集中在工厂类,便于维护

二、核心实现:支付系统案例

1. 策略接口定义(Strategy)
// 支付策略接口
public interface PaymentStrategy {String pay(double amount);String getStrategyName();
}
2. 具体策略实现(Concrete Strategy)
// 支付宝支付策略
public class AlipayStrategy implements PaymentStrategy {@Overridepublic String pay(double amount) {return "支付宝支付" + amount + "元,订单号:ALIPAY-" + System.currentTimeMillis();}@Override public String getStrategyName() { return "支付宝"; }
}// 微信支付策略
public class WechatPayStrategy implements PaymentStrategy {@Overridepublic String pay(double amount) {return "微信支付" + amount + "元,订单号:WECHAT-" + System.currentTimeMillis();}@Override public String getStrategyName() { return "微信支付"; }
}
3. 工厂模式实现(Factory)
public class PaymentStrategyFactory {// 策略缓存(单例模式+工厂模式)private static final Map<String, PaymentStrategy> STRATEGY_CACHE = new HashMap<>();private static final PaymentStrategyFactory INSTANCE = new PaymentStrategyFactory();private PaymentStrategyFactory() {// 注册所有策略(可从配置文件加载)registerStrategy("ALIPAY", new AlipayStrategy());registerStrategy("WECHAT", new WechatPayStrategy());}// 注册策略public void registerStrategy(String type, PaymentStrategy strategy) {STRATEGY_CACHE.put(type, strategy);}// 获取策略(工厂核心方法)public PaymentStrategy getStrategy(String type) {if (!STRATEGY_CACHE.containsKey(type)) {throw new IllegalArgumentException("不支持的支付方式:" + type);}return STRATEGY_CACHE.get(type);}// 获取工厂实例(单例)public static PaymentStrategyFactory getInstance() {return INSTANCE;}
}
4. 上下文类(Context)

(这里通过Context调用工厂还是非常有必要的,可以参考另外一篇:工厂模式中使用Map管理策略实例时,为何仍需要Context?)

public class PaymentContext {private final PaymentStrategyFactory factory;private PaymentStrategy strategy;public PaymentContext(PaymentStrategyFactory factory) {this.factory = factory;}// 通过工厂设置策略public void setStrategy(String type) {this.strategy = factory.getStrategy(type);}// 执行支付public String executePayment(double amount) {return strategy.pay(amount);}
}
5. 客户端调用(Client)
public class Client {public static void main(String[] args) {// 获取工厂实例PaymentStrategyFactory factory = PaymentStrategyFactory.getInstance();// 创建上下文并传入工厂PaymentContext context = new PaymentContext(factory);// 使用支付宝支付context.setStrategy("ALIPAY");String result = context.executePayment(299.5);System.out.println(result);// 动态切换为微信支付context.setStrategy("WECHAT");result = context.executePayment(19.9);System.out.println(result);}
}

三、组合模式的类图解析

1
n
1
1
1
1
PaymentStrategy
+pay(amount: double)
+getStrategyName()
AlipayStrategy
+pay(amount: double)
+getStrategyName()
WechatPayStrategy
+pay(amount: double)
+getStrategyName()
PaymentStrategyFactory
-STRATEGY_CACHE: Map
-INSTANCE: PaymentStrategyFactory
+registerStrategy(type: String, strategy: PaymentStrategy)
+getStrategy(type: String)
+getInstance()
PaymentContext
-factory: PaymentStrategyFactory
-strategy: PaymentStrategy
+setStrategy(type: String)
+executePayment(amount: double)

核心关系

  1. 工厂类创建并管理策略实例
  2. 上下文类通过工厂获取策略
  3. 客户端只需与上下文和工厂交互,无需接触具体策略类

四、组合模式的优势:比单独使用强在哪?

1. 客户端代码简化对比

单独使用策略模式(需要手动创建策略)

// 客户端需要知道具体策略类并手动创建
PaymentContext context = new PaymentContext(new AlipayStrategy());

结合工厂模式(通过工厂获取策略)

// 客户端无需知道策略类,只需传入类型
context.setStrategy("ALIPAY");
2. 策略管理集中化
  • 策略注册、创建、缓存都在工厂类中完成
  • 支持策略的热插拔(如从配置文件动态加载策略)
3. 支持高级特性
  • 策略实例缓存(避免重复创建)
  • 策略版本管理(如支付宝策略升级时不影响客户端)
  • 策略权限控制(通过工厂限制可用策略)

五、高级应用:策略工厂的扩展实现

1. 枚举策略工厂(更简洁的实现)
public enum PaymentStrategyEnum {ALIPAY(new AlipayStrategy()),WECHAT(new WechatPayStrategy());private final PaymentStrategy strategy;PaymentStrategyEnum(PaymentStrategy strategy) {this.strategy = strategy;}public PaymentStrategy getStrategy() {return strategy;}// 通过类型获取策略public static PaymentStrategy getStrategy(String type) {for (PaymentStrategyEnum e : values()) {if (e.name().equals(type)) {return e.strategy;}}throw new IllegalArgumentException("不支持的策略:" + type);}
}// 客户端调用
PaymentStrategy strategy = PaymentStrategyEnum.getStrategy("ALIPAY");
2. 基于注解的策略工厂(自动化注册)
// 策略注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {String value();
}// 策略实现类
@Strategy("ALIPAY")
public class AlipayStrategy implements PaymentStrategy { /*...*/ }// 工厂类(通过反射自动注册策略)
public class AutoRegisterStrategyFactory {private static final Map<String, PaymentStrategy> STRATEGY_MAP = new HashMap<>();static {// 扫描所有带@Strategy注解的类并注册List<Class<?>> strategyClasses = ClassScanner.scan("com.example.strategy");for (Class<?> clazz : strategyClasses) {if (clazz.isAnnotationPresent(Strategy.class)) {Strategy annotation = clazz.getAnnotation(Strategy.class);try {PaymentStrategy strategy = (PaymentStrategy) clazz.getDeclaredConstructor().newInstance();STRATEGY_MAP.put(annotation.value(), strategy);} catch (Exception e) {throw new RuntimeException("策略注册失败", e);}}}}// ... 获取策略方法
}

六、实战场景:电商平台的策略组合应用

场景描述

电商平台需要实现:

  1. 多种支付策略(支付宝、微信、银联)
  2. 多种促销策略(满减、打折、优惠券)
  3. 多种配送策略(普通快递、加急快递、自提)
组合模式架构
客户端层
上下文层
策略工厂层
创建
创建
创建
OrderService
OrderContext
支付策略
PaymentStrategyFactory
促销策略
PromotionStrategyFactory
配送策略
DeliveryStrategyFactory

优势

  • 订单处理逻辑与具体策略解耦
  • 新增支付/促销/配送策略时无需修改订单核心代码
  • 工厂类可统一处理策略的权限控制、日志记录等横切关注点

七、组合模式的注意事项

  1. 策略类型的一致性

    • 工厂返回的策略必须实现同一接口,避免类型错误
    • 可通过泛型约束策略类型:
      public interface Strategy<T> { /*...*/ }
      public class StrategyFactory<T extends Strategy> { /*...*/ }
      
  2. 策略实例的线程安全性

    • 若策略是无状态的(如支付策略),可共享同一个实例
    • 若策略有状态,需为每个上下文创建独立实例
  3. 策略版本控制

    • 可在工厂中实现策略的版本管理,如:
      // 获取指定版本的策略
      public PaymentStrategy getStrategy(String type, int version) { /*...*/ }
      

八、总结:策略+工厂的核心价值

这两种模式的组合遵循了以下设计原则:

  • 开闭原则:新增策略无需修改工厂和上下文
  • 依赖倒置原则:客户端依赖抽象(策略接口)而非具体实现
  • 单一职责原则:策略类专注算法实现,工厂类专注对象创建

在实际开发中,如果遇到以下场景时,可考虑使用策略+工厂的组合模式:

  1. 系统中有多个算法族,且需要动态切换
  2. 希望将算法的创建和使用分离
  3. 避免在客户端代码中出现大量策略类的实例化逻辑

通过这种组合,可以构建出更加灵活、可扩展的系统架构,让代码在面对需求变化时更加从容。

http://www.lqws.cn/news/550981.html

相关文章:

  • yaml 导致的原型污染 -- GPN CTF 2025 Secure by Default
  • 《高等数学》(同济大学·第7版)第九章 多元函数微分法及其应用第五节多元函数微分学的几何应用
  • Redis 单线程的“天花板”与集群的必要性
  • 三、java项目自动部署流水线搭建
  • oracle内存参数调整
  • 【C++】string的模拟实现
  • 关于css的height:100%
  • 助力高考,利用python获取本专科专业选考科目要求
  • 开疆智能CCLinkIE转ModbusTCP网关连接组态王配置案例
  • 开源 java android app 开发(十三)绘图定义控件、摇杆控件的制作
  • Ollama+Gemma3模型+Open WebUI,无公网IP如何内网穿透远程访问?
  • 【Linux 设备模型框架 kobject 和 kset】
  • Java 大视界 -- Java 大数据在智能安防视频监控系统中的目标轨迹预测与防范策略制定(325)
  • 【k近邻】 K-Nearest Neighbors算法原理及流程
  • 机器学习3——参数估计之极大似然估计
  • C++并发编程-4.unique_lock,共享锁和递归锁
  • 详解HashMap底层原理
  • 电脑远程控制另一台电脑无法连接怎么办
  • PostgreSQL 容器化分布式技术方案
  • 基于51单片机-蜂鸣器演奏《飞雪玉花》
  • 什么是故障注入测试
  • 强化联邦学习的车联网 DDoS 攻击检测
  • 【图像处理入门】12. 综合项目与进阶:超分辨率、医学分割与工业检测
  • FLUX.1 Kontext(Dev 版)训练lora基础教程
  • TiDB AUTO_RANDOM 超大主键前端精度丢失排查:JavaScript Number 限制与解决方案
  • 内测开启!看海量化回测系统V2.0版本更新,基于miniQMT的回测系统问世!
  • Threejs开发指南(第七篇 利用AI进行threejs开发)
  • 封装nuxt3的SSR请求和CSR请求方法
  • 1 Studying《Is Parallel Programming Hard》6-9
  • 双指针技巧深度解析