Java设计模式详解:策略模式(Strategy Pattern)
在软件开发中,设计模式是解决常见问题的经典方法。策略模式(Strategy Pattern)作为一种行为型设计模式,能够将算法或行为的定义与使用分离,使得算法可以独立于客户端代码进行变化和扩展。本文将深入解析策略模式的核心思想、实现方式以及实际应用场景,并通过代码示例帮助读者掌握其用法。
一、策略模式的核心思想
策略模式的核心思想是:将不同的行为或算法封装为独立的对象,通过上下文动态选择和执行这些策略。这种模式通过解耦业务逻辑与具体算法,使得程序可以在运行时灵活切换算法,而无需修改客户端代码。
1.1 核心角色
策略模式包含以下三个主要角色:
- 抽象策略(Strategy):定义算法的公共接口,是所有具体策略的抽象。
- 具体策略(Concrete Strategy):实现抽象策略接口,提供具体的算法实现。
- 上下文(Context):持有策略对象的引用,负责调用策略,并将算法的选择与执行委托给策略对象。
二、策略模式的结构
策略模式的结构通常如下:
// 抽象策略接口
public interface Strategy {void execute();
}// 具体策略A
public class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("执行策略A");}
}// 具体策略B
public class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("执行策略B");}
}// 上下文类
public class Context {private Strategy strategy;public void setStrategy(Strategy strategy) {this.strategy = strategy;}public void executeStrategy() {if (strategy == null) {throw new IllegalStateException("策略未设置");}strategy.execute();}
}
2.1 客户端代码
客户端通过上下文动态选择策略:
public class Client {public static void main(String[] args) {Context context = new Context();// 使用策略Acontext.setStrategy(new ConcreteStrategyA());context.executeStrategy(); // 输出: 执行策略A// 切换为策略Bcontext.setStrategy(new ConcreteStrategyB());context.executeStrategy(); // 输出: 执行策略B}
}
三、策略模式的优点与缺点
3.1 优点
- 算法可自由切换:客户端可以在不修改代码的情况下动态切换算法。
- 避免多重条件判断:通过策略模式可以减少
if-else
或switch-case
语句的使用,提升代码可读性。 - 扩展性好:新增策略时只需添加新的具体策略类,无需修改现有代码,符合开闭原则。
- 符合单一职责原则:每个策略类只负责一个具体的算法,职责清晰。
3.2 缺点
- 客户端需了解所有策略类:客户端需要知道所有可用的策略类,并在运行时选择合适的策略。
- 类数量增加:策略模式会增加系统中的类数量,可能导致类膨胀,尤其在策略较多时。
四、策略模式的实际应用场景
策略模式适用于以下场景:
- 需要在不同情况下使用不同的算法:例如支付系统中的多种支付方式(微信支付、支付宝支付、信用卡支付等)。
- 有许多相关类仅在行为上不同:例如电商系统中的折扣策略(会员折扣、季节折扣、满减折扣等)。
- 需要避免复杂的条件语句:例如根据用户类型(普通用户、VIP用户、超级用户)选择不同的权限校验策略。
4.1 示例:支付系统的策略模式
假设我们需要实现一个支付系统,支持多种支付方式(微信支付、支付宝支付、信用卡支付):
4.1.1 抽象策略接口
public interface PaymentStrategy {void pay(double amount);
}
4.1.2 具体策略类
public class WeChatPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("使用微信支付 " + amount + " 元");}
}public class AlipayPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("使用支付宝支付 " + amount + " 元");}
}public class CreditCardPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("使用信用卡支付 " + amount + " 元");}
}
4.1.3 上下文类
public class PaymentContext {private PaymentStrategy paymentStrategy;public PaymentContext(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void executePayment(double amount) {paymentStrategy.pay(amount);}
}
4.1.4 客户端代码
public class Client {public static void main(String[] args) {PaymentContext context = new PaymentContext(new WeChatPayment());context.executePayment(100.0); // 输出: 使用微信支付 100.0 元context.setPaymentStrategy(new AlipayPayment());context.executePayment(200.0); // 输出: 使用支付宝支付 200.0 元context.setPaymentStrategy(new CreditCardPayment());context.executePayment(300.0); // 输出: 使用信用卡支付 300.0 元}
}
五、策略模式的变体与优化
5.1 结合工厂模式
为了进一步简化客户端代码,可以将策略的创建与使用分离,结合工厂模式实现策略的动态生成:
接口
public interface PaymentStrategy {void pay(double amount);
}
实现类具体策略类
public class WeChatPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("使用微信支付 " + amount + " 元");}
}
public class AlipayPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("使用支付宝支付 " + amount + " 元");}
}
public class CreditCardPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("使用信用卡支付 " + amount + " 元");}
}
上下文类
public class PaymentContext {private PaymentStrategy paymentStrategy;public PaymentContext(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void executePayment(double amount) {paymentStrategy.pay(amount);}
}
策略工厂
public class PaymentStrategyFactory {public static PaymentStrategy createPaymentStrategy(String paymentType) {return switch (paymentType.toLowerCase()) {case "wechat" -> new WeChatPayment();case "alipay" -> new AlipayPayment();case "creditcard" -> new CreditCardPayment();default -> throw new IllegalArgumentException("不支持的支付类型: " + paymentType);};}
}
客户端
public class Client {public static void main(String[] args) {// 使用工厂创建支付策略PaymentStrategy wechatStrategy = PaymentStrategyFactory.createPaymentStrategy("wechat");PaymentContext context = new PaymentContext(wechatStrategy);context.executePayment(100.0); // 输出: 使用微信支付 100.0 元// 动态切换支付策略context.setPaymentStrategy(PaymentStrategyFactory.createPaymentStrategy("alipay"));context.executePayment(200.0); // 输出: 使用支付宝支付 200.0 元// 再次切换context.setPaymentStrategy(PaymentStrategyFactory.createPaymentStrategy("creditcard"));context.executePayment(300.0); // 输出: 使用信用卡支付 300.0 元}
}
5.2 使用Lambda表达式简化策略模式
在Java 8及以上版本中,可以通过Lambda表达式简化策略的实现,减少类的冗余:
public class LambdaStrategyExample {public static void main(String[] args) {// 使用Lambda表达式定义策略PaymentStrategy customStrategy = (amount) -> {System.out.println("使用自定义支付方式支付 " + amount + " 元");};PaymentContext context = new PaymentContext(customStrategy);context.executePayment(500.0); // 输出: 使用自定义支付方式支付 500.0 元}
}
六、策略模式与Java内置的策略应用
6.1 Comparator
接口
Java标准库中的Comparator
接口是策略模式的经典应用。通过Comparator
,我们可以动态定义排序规则:
List<String> list = Arrays.asList("apple", "banana", "cherry");
Collections.sort(list, (a, b) -> a.length() - b.length()); // 按长度排序
七、总结
策略模式是一种灵活且强大的设计模式,能够帮助开发者将算法与业务逻辑解耦,实现动态切换行为。以下是策略模式的关键点总结:
- 适用场景:需要动态切换算法、避免复杂条件语句、扩展性强的场景。
- 优点:算法独立、可替换、符合开闭原则。
- 缺点:类数量增加、客户端需了解所有策略类。
通过合理使用策略模式,可以显著提升代码的灵活性和可维护性。在实际开发中,策略模式常与工厂模式、代理模式等结合使用,以进一步增强系统的扩展性和可配置性。掌握策略模式,将为你的Java开发之路增添一把利器!
相关文章:
Java设计模式详解:策略模式(Strategy Pattern)
在软件开发中,设计模式是解决常见问题的经典方法。策略模式(Strategy Pattern)作为一种行为型设计模式,能够将算法或行为的定义与使用分离,使得算法可以独立于客户端代码进行变化和扩展。本文将深入解析策略模式的核心…...

【春秋云镜】CVE-2022-26965 靶场writeup
知识点 网站的主题或者模块位置一般是可以上传文件的,不过一般为压缩包形式主题或者模块可以上github上找到和cms匹配的源码主题被解压后会放到加入到对应的文件夹中,而且还会自动执行对应的info.php文件(需要主题和cms配套才行)我这里取巧了࿰…...
爬虫的几种方式(使用什么技术来进行一个爬取数据)
在网页数据爬取中,确实存在多种数据呈现和获取形式,远不止静态HTML解析和简单JS渲染。理解这些形式对于应对不同的反爬机制至关重要: 主要数据获取形式与应对策略 纯静态HTML (基础形式) 特点: 数据直接嵌入在服务器返回的初始HT…...
XML 编码:结构化数据的基石
XML 编码:结构化数据的基石 引言 XML(可扩展标记语言)作为互联网上广泛使用的数据交换格式,已经成为结构化数据存储和传输的重要工具。本文旨在深入探讨XML编码的原理、应用场景以及编码规范,帮助读者更好地理解和运用XML。 XML编码概述 1. XML的起源 XML诞生于1998年…...
nt!CcGetVacbMiss函数分析之设置好nt!_VACB然后调用函数nt!SetVacb
第一部分:MmMapViewInSystemCache函数返回 Status MmMapViewInSystemCache (SharedCacheMap->Section, &Vacb->BaseAddress, &NormalOffset, …...

JSP、HTML和Tomcat
9x9上三角乘法表 乘法表的实现 <% page contentType"text/html;charsetUTF-8" language"java" %> <!DOCTYPE html> <html> <head><title>99 上三角乘法表</title><style>body {font-family: monospace;padding…...

(1)pytest简介和环境准备
1. pytest简介 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高。根据pytest的官方网站介绍,它具有如下特点: 非常容易上手,入门简单&a…...
Git 入门学习教程
Git 入门学习教程 什么是 Git? Git 是一个分布式版本控制系统,由 Linus Torvalds 为 Linux 内核开发而创建。它可以帮助开发者: 跟踪代码变化协作开发项目回退到之前的版本创建分支进行实验性开发 安装 Git Windows 下载 Git for Windo…...

构建高性能风控指标系统
一、引言 在金融风控领域,指标是风险识别的核心依据。风控平台核心系统之一--规则引擎的运行依赖规则、变量和指标,一个高性能的指标系统非常重要,本文将深入探讨风控平台指标系统的全链路技术实现,涵盖从指标配置到查询优化的完…...
openfeignFeign 客户端禁用 SSL
要针对特定的 Feign 客户端禁用 SSL 验证,可以通过自定义配置类实现。以下是完整解决方案: 1. 创建自定义配置类(禁用 SSL 验证) import feign.Client; import feign.httpclient.ApacheHttpClient; import org.apache.http.conn…...
DeepSeek 赋能自动驾驶仿真测试:解锁高效精准新范式
目录 一、自动驾驶仿真测试概述1.1 自动驾驶发展现状1.2 自动驾驶仿真测试流程 二、DeepSeek 技术剖析2.1 DeepSeek 简介2.2 DeepSeek 核心技术原理 三、DeepSeek 在自动驾驶仿真测试中的应用原理3.1 与自动驾驶仿真测试流程的结合点3.2 如何提升仿真测试效果 四、DeepSeek 在自…...

晨控CK-UR12与西门子PLC配置Modbus TCP通讯连接操作手册
晨控CK-UR12与西门子PLC配置Modbus TCP通讯连接操作手册 晨控CK-UR12系列作为晨控智能工业级别RFID读写器,支持大部分工业协议如RS232、RS485、以太网。支持工业协议Modbus RTU、Modbus TCP、Profinet、EtherNet/lP、EtherCat以及自由协议TCP/IP等。 本期主题:围绕…...

实验一:PyTorch基本操作实验
import torch # PyTorch中初始化矩阵常见有以下几种方法 # 1. 直接使用固定值初始化 # M torch.tensor([[1.0, 2.0, 3.0]]) # 1x3矩阵 # 2. 随机初始化 # M torch.rand(1, 3) # 1x3矩阵,元素在0-1之间均匀分布 # M torch.randn(1, 3) # 1x3矩阵,元…...

可视化大屏通用模板Axure原型设计案例
本文将介绍一款基于Axure设计的可视化大屏通用模板,适用于城市、网络安全、园区、交通、社区、工业、医疗、能源等多个领域。 模板概述 这款Axure可视化大屏通用模板集成了多种数据展示模块和组件,旨在为用户提供一个灵活、可定制的数据展示平台。无论…...
通配符(Wildcard)与正则表达式(Regular Expression)的关系及区别
通配符(Wildcard)与正则表达式(Regular Expression)的关系及区别 1. 通配符(Wildcard) 定义:通配符是用于简单模式匹配的特殊符号,主要用于文件名匹配(如命令行操作&…...

历年山东大学计算机保研上机真题
历年山东大学计算机保研上机真题 2025山东大学计算机保研上机真题 2024山东大学计算机保研上机真题 2023山东大学计算机保研上机真题 在线测评链接:https://pgcode.cn/school 从1到100找质数 题目描述 从 1 1 1 到 100 100 100 中找出所有的质数。 输入格式 …...

Java处理动态的属性:字段不固定、需要动态扩展的 JSON 数据结构
文章目录 引言I `JSONObject` 接收和返回JSONObject 接收和返回数据存储II 签名测试接口dto的定义签名计算III JsonAnySetter 和JsonAnyGetter 注解@JsonAnySetter 的用法@JsonAnyGetter 的用法综合示例引言 应用场景: 签名测试接口、表单配置项、参数列表、插件信息等。技术实…...

MAC电脑怎么通过触摸屏打开右键
在Mac电脑上,通过触摸屏打开右键菜单的方法如下: 法1:双指轻点:在触控板上同时用两根手指轻点,即可触发右键菜单。这是Mac上常用的右键操作方法。 法2:自定义触控板角落:可以设置触控板的右下角或左下角作为右键区域…...

用 Whisper 打破沉默:AI 语音技术如何重塑无障碍沟通方式?
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...

【东枫科技】KrakenSDR 天线阵列设置
标准测向需要五根相同的全向天线。您可以折衷使用更少的天线,但为了获得最佳性能,我们建议使用全部五根天线。这些天线通常是磁铁安装的鞭状天线,或偶极子天线。我们建议始终使用均匀圆形阵列 (UCA) 天线,因为它可以确定来自各个方…...
Spring Boot中的事件与JMS消息集成
Spring Boot事件机制 Spring框架的事件处理是其核心特性之一,通过ApplicationEvent类和ApplicationListener接口实现。在Spring Boot应用中,事件机制是实现模块间消息传递的重要方式,通常用于业务逻辑内部通信。 内置事件类型 Spring应用上下文在启动时会触发多种内置事件…...
ubuntu/windows系统下如何让.desktop/.exe文件 在开机的时候自动运行
目录 1,让 .desktop 文件在 Ubuntu 开机时自动启动 1.1 创建 autostart 目录(如果不存在) 1.2 将 .desktop 文件复制到 autostart 目录 1.3 确保 .desktop 文件有可执行权限 2,windows 2.1 打开「启动」文件夹: 2.2 将 .exe 或快捷方…...

云计算数据治理
知识星球:数据书局。打算通过知识星球将这些年积累的知识、经验分享出来,让各位在数据治理、数据分析的路上少走弯路,另外星球也方便动态更新最近的资料,提供各位一起讨论数据的小圈子 1.摘要 云计算可以推动创新和各行业应用的…...
【Net】TCP粘包与半包
文章目录 TCP粘包与半包1 背景2 粘包(packet stick)3 半包(packet split)4 为什么会出现粘包/半包?5 如何解决?6 示例7 总结 TCP粘包与半包 在网络编程中,粘包和半包问题是常见的 TCP 协议特有…...

【Android】如何抓取 Android 设备的 UDP/TCP 数据包?
目录 前言理解抓包tcpdump 实时抓包Wireshark 解包抓包后的一些思考 前言 在真正接触 UDP/TCP 抓包之前,我一直以为这是一项高深莫测的技术。可当我们真正了解之后才发现,其实并没有那么复杂——不过如此。 所谓的大佬,往往只是掌握了你尚未…...
深度解析 Nginx 配置:从性能优化到 HTTPS 安全实践
引言 Nginx 作为高性能的 Web 服务器和反向代理,其配置灵活性和强大功能备受开发者青睐。本文基于一份生产环境的 Nginx 配置文件,详细拆解其核心配置逻辑,涵盖性能优化、HTTPS 安全配置、反向代理及静态资源处理等关键环节,帮助…...
触发器与存储过程详解
触发器与存储过程详解 1. 触发器(Trigger)基础概念 1.1 定义与特性 go专栏:https://duoke360.com/tutorial/path/golang 触发器是数据库中的一种特殊存储程序,它在特定数据库事件(如INSERT、UPDATE、DELETE)发生时自动执行。触发器具有以下核心特性: 事件驱动:与表事件绑…...
游戏盾与高防CDN的协同防御策略分析
游戏盾与高防CDN的协同防御策略可以从技术互补性、分层防护机制、动态流量调度等角度展开分析,以下为核心要点: 1. 分层防御架构:流量分层过滤 高防CDN边缘层:利用全球分布的边缘节点作为“第一道防线”…...

Scratch节日 | 六一儿童节射击游戏
六一儿童节快乐!这款超有趣的 六一儿童节射击游戏,让你变身小猫弓箭手,守护节日的快乐时光! 🎮 游戏玩法 上下方向键:控制小猫的位置,自由移动,瞄准目标! 空格键&#…...

GPU层次结构(Nvidia和Apple M芯片,从硬件到pytorch)
这里写目录标题 0、驱动pytorch环境安装验证1.window环境2.Mac Apple M芯片环境 1、Nvidia显卡驱动、CUDA、cuDNN关系汇总1**1. Nvidia显卡驱动(Graphics Driver)****2. CUDA(Compute Unified Device Architecture)****3. cuDNN&a…...