【设计模式】三十二、策略模式
系列文章|源码
https://github.com/tyronczt/design-mode-learn
文章目录
- 系列文章|源码
- 一、模式定义与核心思想
- 二、模式结构与Java实现
- 1. 核心角色
- 2. Java代码示例
- 三、策略模式的五大核心优势
- 四、适用场景
- 五、与其他模式的对比
- 六、最佳实践建议
- 总结
- 🚀进阶版【更符合实际开发】🚀
- 策略+工厂模式
- 效果图
- 类图
- 控制器
- 策略工厂
- 策略接口
- 策略实现类
- 枚举类
- Spring工具类
一、模式定义与核心思想
策略模式(Strategy Pattern) 是一种行为型设计模式,其核心思想是将一组算法或行为封装为独立的策略类,使得它们可以相互替换,且算法的变化独立于使用它的客户端。该模式通过组合替代继承,符合开闭原则(对扩展开放、对修改关闭)。
二、模式结构与Java实现
1. 核心角色

• 策略接口(Strategy):定义算法族的公共行为(如PaymentStrategy接口)。
• 具体策略类(Concrete Strategy):实现接口的具体算法(如微信支付、支付宝支付)。
• 上下文类(Context):持有策略引用,动态切换算法(如PaymentContext类)。
2. Java代码示例
以下以支付方式选择为例展示实现:
// 1. 策略接口(定义支付行为)
public interface IPaymentStrategy {void pay(double amount);
}// 2. 具体策略类(微信支付)
public class WeChatPayStrategy implements IPaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("微信支付:" + amount + "元");}
}// 3. 具体策略类(支付宝支付)
public class AliPayStrategy implements IPaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("支付宝支付:" + amount + "元");}
}// 4. 上下文类(管理策略)
public class PaymentContext {private IPaymentStrategy strategy;public void setStrategy(IPaymentStrategy strategy) {this.strategy = strategy;}public void executePayment(double amount) {if (strategy != null) {strategy.pay(amount);} else {throw new IllegalStateException("未选择支付方式");}}
}// 5. 客户端调用
public class Client {public static void main(String[] args) {PaymentContext context = new PaymentContext();context.setStrategy(new WeChatPayStrategy());context.executePayment(100.0); // 输出:微信支付:100.0元context.setStrategy(new AliPayStrategy());context.executePayment(200.0); // 输出:支付宝支付:200.0元}
}

三、策略模式的五大核心优势
- 消除复杂条件分支
• 传统方式需通过大量if-else判断不同场景(如支付方式选择),策略模式将每个算法封装为独立类,代码更清晰。 - 符合开闭原则(OCP)
• 扩展性高:新增策略(如银行卡支付)只需添加新类,无需修改现有代码。
• 维护性高:修改某一策略的逻辑不会影响其他策略。 - 动态切换算法
• 运行时通过setStrategy()方法灵活切换策略(如根据用户选择切换支付方式)。 - 算法复用与解耦
• 不同上下文可共享同一策略(如多个订单系统共用支付策略)。
• 算法实现与业务逻辑解耦,便于单元测试。 - 减少重复代码
• 公共逻辑可抽取至抽象类(如支付前的参数校验),具体策略类仅关注核心算法。
四、适用场景
- 多算法动态选择:如支付方式、数据加密算法、排序算法等。
- 业务规则频繁变化:如电商促销策略(满减、折扣、积分)。
- 替代复杂条件分支:避免多个
if-else或switch-case语句。
五、与其他模式的对比
| 模式 | 核心区别 | 典型场景 |
|---|---|---|
| 策略模式 | 关注算法族动态切换 | 支付方式、折扣策略 |
| 状态模式 | 关注状态驱动的行为变化 | 订单状态流转、游戏角色 |
| 工厂模式 | 关注对象创建 | 策略类的实例化管理 |
六、最佳实践建议
• 结合工厂模式:使用策略工厂统一管理策略实例(如通过Map存储策略类)。
• 默认策略:在上下文中设置默认策略以避免空指针异常。
• 策略组合:复杂场景可将多个策略组合使用(如先满减再折扣)。
总结
策略模式通过封装算法和动态切换机制,显著提升了代码的可维护性与扩展性。在Java中,结合接口与多态特性,能高效实现复杂的业务需求(如电商支付、促销活动)。其核心价值在于将“做什么”与“怎么做”分离,是应对算法灵活性和业务变化的利器。
🚀进阶版【更符合实际开发】🚀
策略+工厂模式
效果图
实际开发中只要前端传入支付类型,后端即可根据策略进行相应支付逻辑处理。

类图

控制器
@RestController
public class AdvancedClientController {@Resourceprivate PaymentHandleStrategyFactory paymentHandlerFactory;@GetMapping("/pay")public void pay(int code, double amount) {String paymentType = PaymentEnum.getPaymentNameByCode(code);if (paymentType != null) {// 根据支付方式选择支付处理器IPaymentHandleStrategy paymentHandleStrategy = paymentHandlerFactory.getPaymentHandleStrategy(paymentType);paymentHandleStrategy.pay(amount);}}
}
策略工厂
@Slf4j
@Service
public class PaymentHandleStrategyFactory {/*** 根据支付类型获取相应的处理策略** @param type 支付类型,用于确定使用哪种策略处理支付请求* @return IPaymentHandleStrategy 实现类,用于处理特定支付类型的策略*/public IPaymentHandleStrategy getPaymentHandleStrategy(String type) {// 根据传入的类型参数选择并返回对应的支付处理策略// AliPay+HandleStrategyImplIPaymentHandleStrategy iPaymentHandleStrategy = SpringContextUtil.getBean(type + "HandleStrategyImpl");// 检查 iPaymentHandleStrategy 是否为空,并增加防御性编程if (iPaymentHandleStrategy == null || StringUtils.isEmpty(iPaymentHandleStrategy)) {log.warn("getDatasetHandleStrategy error. type:{}", type);throw new RuntimeException("getDatasetHandleStrategy error. type:" + type);}return iPaymentHandleStrategy;}
}
策略接口
public interface IPaymentHandleStrategy {void pay(double amount);
}
策略实现类
@Service
public class AliPayHandleStrategyImpl implements IPaymentHandleStrategy {@Overridepublic void pay(double amount) {System.out.println("【策略+工厂】支付宝支付:" + amount + "元");}
}@Service
public class WeChatPayHandleStrategyImpl implements IPaymentHandleStrategy {@Overridepublic void pay(double amount) {System.out.println("【策略+工厂】微信支付:" + amount + "元");}
}
枚举类
package com.tyron.design.mode.learn.advanced.enums;public enum PaymentEnum {// 微信支付WE_CHAT_PAY(1, "weChatPay", "微信支付"),// 支付宝支付ALI_PAY(2, "aliPay", "支付宝支付");private int code;private String name;private String desc;PaymentEnum(int code, String name, String desc) {this.code = code;this.name = name;this.desc = desc;}public int getCode() {return code;}public String getName() {return name;}public String getDesc() {return desc;}/*** 根据code获取枚举常量*/public static PaymentEnum getPaymentEnumByCode(int code) {for (PaymentEnum paymentEnum : PaymentEnum.values()) {if (paymentEnum.getCode() == code) {return paymentEnum;}}return null;}/*** 根据code获取枚举常量的name属性** @param code* @return*/public static String getPaymentNameByCode(int code) {for (PaymentEnum paymentEnum : PaymentEnum.values()) {if (paymentEnum.getCode() == code) {return paymentEnum.getName();}}return null;}
}
Spring工具类
package com.tyron.design.mode.learn.util;import lombok.NonNull;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;@Component("SpringUtil")
public class SpringContextUtil implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {context = applicationContext;}@SuppressWarnings("unchecked")public static <T> T getBean(String beanName) {if (context.containsBean(beanName)) {return (T)context.getBean(beanName);} else {return null;}}
}
详细代码已上传 Github:https://github.com/tyronczt/design-mode-learn/tree/main/design-mode-learn-3_2
相关文章:
【设计模式】三十二、策略模式
系列文章|源码 https://github.com/tyronczt/design-mode-learn 文章目录 系列文章|源码一、模式定义与核心思想二、模式结构与Java实现1. 核心角色2. Java代码示例 三、策略模式的五大核心优势四、适用场景五、与其他模式的对比六、最佳实践建议总结 🚀进阶版【更…...
Cyberchef实用功能之-json line格式文件美化和查询
本文将介绍一下如何使用cyberchef对json line格式数据进行美化方便阅读,以及json line格式数据的批量查询操作。 之前的文章介绍了json格式数据的美化和查询,即Cyberchef实用功能之-json解析美化和转换,Cyberchef实用功能之-批量提取json数据…...
Java求101-200之间有多少素数
Java学习笔记 今天看教程看到了这个题,对于一名打过算法竞赛的选手还是很简单的,但由于之前是c组的,所以用java写一下,练一下手。 代码: package com.itheima.hello;public class Test1 {public static void main(S…...
计算机基础:编码03,根据十进制数,求其原码
专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏,故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 (一)WIn32 专栏导航 上一篇:计算机基础:编码02,有符号数编码…...
FaryGui文字shader修改,弧线排列
因项目要求,希望将文字进行标题那样的弧线排列,如下图: 对FaryGUI的文字Shader进行了一些修改,基本达到要求,shader设置如下: shader代码如下: // Upgrade NOTE: replaced _Object2World with unity_ObjectToWorld // Upgrade NOTE: replaced mul(UNITY_MATRIX_MVP,*) with Un…...
QT笔记---JSON
QT笔记---JSON JSON1、JSON基本概念1.1、判断.json文件工具 2、生成.json数据3、解析.json数据 JSON 在现代软件开发中,数据的交换和存储格式至关重要。JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,以其简洁易…...
C++ string的模拟实现
Hello!!大家早上中午晚上好,昨天复习了string的使用,今天来模拟实现一下string!!! 一、string的框架搭建 1.1首先我们需要一个string的头文件用来做变量、函数、类等声明;再需要一个test文件来做测试,还需…...
使用LangChain实现基于LLM和RAG的PDF问答系统
目录 前言一.大语言模型(LLM)1. 什么是LLM?2. LLM 的能力与特点 二、增强检索生成(RAG)三. 什么是 LangChain?1. LangChain 的核心功能2. LangChain 的优势3. LangChain 的应用场景4. 总结 四.使用 LangChain 实现基于 PDF 的问答系统 前言 本文将介绍 …...
图像滤波中常用滤波器的相位响应——不是只有零相位滤波器
实偶函数滤波器 当滤波器是实偶函数时,其滤波结果的相位在通带内为 0 或 π \pi π,正频率和负频率成分的相位相同。这种相位特性使得实偶函数滤波器在低通滤波、平滑处理等需要保持信号相位不失真的应用中非常有用。 实偶函数特性: 滤波器…...
学习CSS滤镜属性 `filter: invert()`
一、核心机制 数学原理 invert(1) 对每个像素的RGB通道执行 颜色反相计算: 新通道值 255 - 原通道值 例如 rgb(255,0,0)(纯红)会转换为 rgb(0,255,255)(青色)。 透明度处理 该滤镜会保留元素的Alpha通道(…...
C++实现rabbitmq生产者消费者
RabbitMQ是一个开源的消息队列系统,它实现了高级消息队列协议(AMQP), 特点 可靠性:通过持久化、镜像队列等机制保证消息不丢失,确保消息可靠传递。灵活的路由:提供多种路由方式,如…...
在VMware上部署【Ubuntu】
镜像下载 国内各镜像站点均可下载Ubuntu镜像,下面例举清华网站 清华镜像站点:清华大学开源软件镜像站 | Tsinghua Open Source Mirror 具体下载步骤如下: 创建虚拟机 准备:在其他空间大的盘中创建存储虚拟机的目录,…...
【Pandas】pandas Series plot.barh
Pandas2.2 Series Plotting 方法描述Series.plot([kind, ax, figsize, …])用于绘制 Series 对象的数据可视化图表Series.plot.area([x, y, stacked])用于绘制堆叠面积图(Stacked Area Plot)Series.plot.bar([x, y])用于绘制垂直条形图(Ver…...
检索增强生成(2)本地PDF 本地嵌入模型
from langchain_community.document_loaders import PyPDFLoader from pathlib import Pathdef load_local_pdf(file_path):if not Path(file_path).exists():raise FileNotFoundError(f"文件 {file_path} 不存在!")loader PyPDFLoader(file_path)try:do…...
又双叒叕Scrapy爬虫相关的面试题及详细解答
Scrapy是Python开发的一个快速、高层次的网络爬虫框架,专注于高效抓取网页并提取结构化数据。其核心设计基于异步处理机制,适合大规模数据采集任务。 文章目录 基础概念1. Scrapy框架的核心组件有哪些?架构与流程2. 描述Scrapy的工作流程核心组件详解3. 如何自定义Item Pipe…...
【QA】装饰模式在Qt中有哪些运用?
在Qt框架中,装饰模式(Decorator Pattern)主要通过继承或组合的方式实现,常见于IO设备扩展和图形渲染增强场景。以下是Qt原生实现的装饰模式典型案例: 一、QIODevice装饰体系(继承方式) 场景 …...
【保姆级】阿里云codeup配置Git的CI/CD步骤
以下是通过阿里云CodeUp的Git仓库进行CI/CD配置的详细步骤,涵盖前端(Vue 3)和后端(Spring Boot)项目的自动化打包,并将前端打包结果嵌入到Nginx的Docker镜像中,以及将后端打包的JAR文件拷贝至Do…...
使用STM32CubeMX+DMA+空闲中断实现串口接收和发送数据(STM32G070CBT6)
1.STM32CubeMX配置 (1)配置SYS (2)配置RCC (3)配置串口,此处我用的是串口4,其他串口也是一样的 (4)配置DMA,将串口4的TX和RX添加到DMA中 &#…...
【视觉提示学习】3.21论文随想
. . Frontiers of Information Technology & Electronic Engineering. 2024, 25(1): 42-63 https://doi.org/10.1631/FITEE.2300389 中文综述,根据里面的架构,把视觉提示学习分成两类,一类是单模态提示学习(以vit为代表&…...
(一)丶Windows安装RabbitMQ可能会遇到的问题
一丶可能会忘了配置ERLang的环境变量 二丶执行命令时报错 第一步 rabbitmq-plugins enable rabbitmq_management 第二部 rabbitmqctl status 三丶修改.erlang.cookie 文件 1.找到C盘目下的.erlang.cookie文件 C:\Users\admin\.erlang.cookie C:\Windows\System32\config\sys…...
Mistral AI发布开源多模态模型Mistral Small 3.1:240亿参数实现超越GPT-4o Mini的性能
法国人工智能初创公司Mistral AI于2025年3月正式推出新一代开源模型Mistral Small 3.1 ,该模型凭借240亿参数的轻量级设计,在多项基准测试中表现优异,甚至超越了Google的Gemma 3和OpenAI的GPT-4o Mini等主流专有模型。 1、核心特性与优势 多…...
如何在IPhone 16Pro上运行python文件?
在 iPhone 16 Pro 上运行 Python 文件需要借助第三方工具或远程服务,以下是具体实现方法和步骤: 一、本地运行方案(无需越狱) 使用 Python 编程类 App 以下应用可在 App Store 下载,支持直接在 iPhone 上编写并运行 …...
springboot整合mybatis-plus【详细版】
目录 一,简介 1. 什么是mybatis-plus2.mybatis-plus特点 二,搭建基本环境 1. 导入基本依赖:2. 编写配置文件3. 创建实体类4. 编写controller层5. 编写service接口6. 编写service层7. 编写mapper层 三,基本知识介绍 1. 基本注解 T…...
视频剪辑行业的现状与进阶之路:一个双视角分析
视频剪辑行业的现状与进阶之路:一个双视角分析 一、现状解析 商业角度分析 成本控制 培训需要投入时间和人力成本 快节奏的市场环境要求快速产出 人员流动性大,培训投入可能无法获得长期回报 市场需求 大量内容需要快速产出 标准化的剪辑模板更容易管理 …...
k近邻图(knn-graph)和局部线性嵌入图(LLE-graph)的相似性和区别
K 近邻图(KNN - graph)和局部线性嵌入图(LLE - graph)是用于构建数据点之间关系图的两种方法。 1. k近邻图(knn-graph) 核心思想:k近邻图通过计算样本之间的距离来构建图。具体来说,…...
Qt之MVC架构MVD
什么是MVC架构: MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controll…...
使用 Apktool 反编译、修改和重新打包 APK
使用 Apktool 反编译、修改和重新打包 APK 在 Android 逆向工程和应用修改过程中,apktool 是一个强大的工具,它允许我们解包 APK 文件、修改资源文件或代码,并重新打包成可安装的 APK 文件。本文将介绍如何使用 apktool 进行 APK 反编译、修…...
深度解析学术论文成果评估(Artifact Evaluation):从历史到现状
深度解析学术论文成果评估(Artifact Evaluation):从历史到现状 引言 在计算机科学和工程领域的学术研究中,可重复性和可验证性越来越受到重视。随着实验性研究的复杂性不断增加,确保研究成果可以被其他研究者验证和构建变得尤为重要。这一需…...
二分查找上下界问题的思考
背景 最近在做力扣hot100中的二分查找题目时,发现很多题目都用到了二分查找的变种问题,即二分查找上下界问题,例如以下题目: 35. 搜索插入位置 74. 搜索二维矩阵 34. 在排序数组中查找元素的第一个和最后一个位置 它们不同于查找…...
关于FastAPI框架的面试题及答案解析
FastAPl是一个现代、快速(高性能)的Web框架,用于构建API,基于Python3.7+的类型提示功能。它由Python开发者SebastianRamirez创建,并且使用了Starlette作为其核心组件以及Pydantic进行数据验证。 文章目录 基础篇1. FastAPI的核心优势是什么?2. 如何定义一个GET请求路由?…...
