引言:从现实世界到代码世界的面向对象

在商业策略制定中,企业会根据市场环境选择不同的竞争策略;在军事行动中,指挥官会根据敌情选择不同的战术;在游戏对战中,玩家会根据局势调整作战方式。这种根据情境选择不同行为的模式,在软件设计中同样普遍存在。策略模式(Strategy Pattern)正是为解决这类问题而生的经典设计模式。

想象你正在使用导航软件规划路线。同一个目的地,你可以选择:

  • 最快路线:优先考虑时间

  • 最短距离:不考虑路况,只求距离最短

  • 避开高速:宁愿慢些也要省过路费

  • 经济路线:平衡时间和费用

导航软件如何优雅地实现这些不同的路线计算算法?这就是策略模式大显身手的地方。作为行为型设计模式的代表,策略模式让我们能够定义一系列算法,并将每个算法封装起来,使它们可以相互替换。

一、策略模式解决了什么问题?

先看一个常见的反例:

public class Navigator {public void buildRoute(String routeType) {if ("FASTEST".equals(routeType)) {// 复杂的最快路线算法System.out.println("计算最快路线...考虑实时路况");} else if ("SHORTEST".equals(routeType)) {// 最短距离算法System.out.println("计算最短距离...忽略路况");} else if ("ECONOMIC".equals(routeType)) {// 经济路线算法System.out.println("计算经济路线...平衡时间和费用");}// 每新增一种路线类型,就要修改这里}
}

这种实现方式存在几个明显问题:

  1. 违反开闭原则:新增算法需要修改原有类

  2. 代码臃肿:所有算法堆积在一个类中

  3. 难以维护:随着算法增加,条件判断越来越复杂

  4. 复用困难:相同算法难以在其他地方复用

策略模式正好可以解决这些问题。

二、策略模式的核心结构

策略模式在GoF《设计模式》中的正式定义:

定义一系列算法,将每个算法封装起来,并使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户端。

策略模式包含三个核心角色:

  1. Context(上下文):维护对策略对象的引用,负责将客户端请求委托给当前策略

  2. Strategy(策略接口):定义所有支持算法的公共接口

  3. ConcreteStrategy(具体策略):实现策略接口的具体算法类

1. 基础实现

// 策略接口
interface RouteStrategy {void buildRoute(Point start, Point end);
}// 具体策略:最快路线
class FastestRouteStrategy implements RouteStrategy {@Overridepublic void buildRoute(Point start, Point end) {System.out.println("计算最快路线...考虑实时路况");// 实际算法实现}
}// 具体策略:最短距离
class ShortestRouteStrategy implements RouteStrategy {@Overridepublic void buildRoute(Point start, Point end) {System.out.println("计算最短距离...忽略路况");// 实际算法实现}
}// 上下文
class Navigator {private RouteStrategy strategy;public void setStrategy(RouteStrategy strategy) {this.strategy = strategy;}public void buildRoute(Point start, Point end) {if (strategy != null) {strategy.buildRoute(start, end);} else {System.out.println("请先设置路线策略");}}
}// 使用示例
public class Client {public static void main(String[] args) {Navigator navigator = new Navigator();// 使用最快路线策略navigator.setStrategy(new FastestRouteStrategy());navigator.buildRoute(pointA, pointB);// 切换为最短距离策略navigator.setStrategy(new ShortestRouteStrategy());navigator.buildRoute(pointA, pointB);}
}

三、Spring中的策略模式实践

在Spring应用中,我们可以利用DI(依赖注入)更加优雅地实现策略模式:

// 策略接口
public interface DiscountStrategy {BigDecimal applyDiscount(BigDecimal amount);String getStrategyName();
}// 具体策略:会员折扣
@Service
public class MemberDiscountStrategy implements DiscountStrategy {@Overridepublic BigDecimal applyDiscount(BigDecimal amount) {return amount.multiply(new BigDecimal("0.9"));}@Overridepublic String getStrategyName() {return "MEMBER_DISCOUNT";}
}// 具体策略:节日折扣
@Service
public class FestivalDiscountStrategy implements DiscountStrategy {@Overridepublic BigDecimal applyDiscount(BigDecimal amount) {return amount.multiply(new BigDecimal("0.8"));}@Overridepublic String getStrategyName() {return "FESTIVAL_DISCOUNT";}
}// 策略上下文
@Service
public class DiscountContext {private final Map<String, DiscountStrategy> strategyMap;@Autowiredpublic DiscountContext(List<DiscountStrategy> strategies) {this.strategyMap = strategies.stream().collect(Collectors.toMap(DiscountStrategy::getStrategyName,Function.identity()));}public BigDecimal applyDiscount(String strategyName, BigDecimal amount) {DiscountStrategy strategy = strategyMap.get(strategyName);if (strategy == null) {throw new IllegalArgumentException("未知的折扣策略");}return strategy.applyDiscount(amount);}
}// 控制器使用
@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate DiscountContext discountContext;@PostMapping("/checkout")public ResponseEntity<BigDecimal> checkout(@RequestParam String discountType,@RequestParam BigDecimal amount) {BigDecimal finalAmount = discountContext.applyDiscount(discountType, amount);return ResponseEntity.ok(finalAmount);}
}

Spring策略模式优势

  1. 自动收集所有策略实现

  2. 策略与上下文完全解耦

  3. 方便扩展新策略

  4. 策略可以享受Spring的所有特性(AOP、依赖注入等)

四、策略模式的性能考量

4.1 策略对象的创建成本

对于高频调用的策略,需要考虑策略对象的创建方式:

  1. 每次创建新实例:简单但可能产生GC压力

  2. 策略对象复用:适合无状态的策略

  3. 对象池技术:适用于创建成本高的策略

4.2 策略选择的效率

策略选择方式时间复杂度适用场景
if-else/switchO(n)策略数量少(5个以下)
Map查找O(1)策略数量多
策略链O(n)需要依次尝试策略

五、策略模式的优缺点分析 

优势

  1. 开闭原则:无需修改已有代码即可新增策略

  2. 消除条件语句:替代大量的if-else或switch-case

  3. 提高可测试性:每个策略可以独立测试

  4. 运行时灵活性:支持动态切换算法

  5. 代码复用:不同上下文可以共享策略

局限性

  1. 客户端必须了解策略:需要知道不同策略的区别

  2. 策略类增多:可能增加系统中类的数量

  3. 通信开销:策略与上下文可能需要交换数据

  4. 不适合简单算法:可能会过度设计简单场景

六、策略模式与其他模式的关系

6.1与工厂模式的区别

模式关注点应用阶段主要作用
工厂模式对象创建初始化阶段隐藏创建逻辑
策略模式行为算法运行时封装可互换的行为

6.2 与状态模式的对比

相似点:都有上下文和多个实现类
不同点:

  • 状态模式:状态转换通常由上下文内部管理

  • 策略模式:策略选择通常由客户端控制

最后,策略模式不仅仅是一种编码技巧,它体现了"分而治之"的古老智慧。通过将复杂多变的行为分解为独立的策略单元,我们获得了:

  1. 清晰的边界:每个策略只关注自己的算法

  2. 灵活的组合:可以像乐高积木一样搭配策略

  3. 可控的变化:算法变化被隔离在策略内部

正如《孙子兵法》所言:"兵无常势,水无常形",软件设计也应该能够随需而变。策略模式正是帮助我们实现这种灵活性的利器。

设计模式的最高境界是"无招胜有招"——不是机械地套用模式,而是理解其思想后自然地融入设计中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87451.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87451.shtml
英文地址,请注明出处:http://en.pswp.cn/web/87451.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Bitvisse SSH Client 安装配置文档

一、软件功能介绍​ Bitvisse SSH Client 是一款功能强大的 SSH 客户端软件&#xff0c;具备以下显著特点&#xff1a;​ 丰富的代理隧道协议支持&#xff1a;支持 socks4、socks4a、socks5 和 http 等多种连接代理隧道协议&#xff0c;为网络连接提供多样选择。​便捷的应用…

DataGear 5.4.1 发布,数据可视化分析平台

DataGear 数据可视化分析平台 5.4.1 发布&#xff0c;BUG修复&#xff0c;具体更新内容如下&#xff1a; 修复&#xff1a;修复SQL数据集使用预编译语法后SQL关键字防注入功能不起作用的BUG&#xff1b;修复&#xff1a;修复内置图表选项disableSetting在图表展示页不起作用的…

Visual Studio install 解决进度条不加载,自动安装失败导致软件无法打开问题

路径 C:\Windows\System32\drivers\etc修改hosts文件&#xff0c;需要右键管理员权限打开。 # Copyright (c) 1993-2009 Microsoft Corp. # # This is a sample HOSTS file used by Microsoft TCP/IP for Windows. # # This file contains the mappings of IP addresses to h…

关于小波降噪、小波增强、小波去雾的原理区分

在传统的图像处理中使用小波分解是一种常见的方法。经常分不清小波降噪和小波增强的区别&#xff0c;简单记录下二者的区别同时再记录一下小波去雾的原理。一、小波降噪原理信号分解小波降噪基于小波变换。它将含噪信号分解成不同尺度&#xff08;频率&#xff09;下的小波系数…

Python商务数据分析——Matplotlib 数据可视化学习笔记

一、Matplotlib 基础认知 1.1 库功能与定位 核心作用&#xff1a;将数据可视化展示&#xff0c;提升数据直观性与说服力 应用场景&#xff1a;绘制折线图、饼图、柱状图等 2D/3D 图表 双接口模式&#xff1a; MATLAB 风格&#xff1a;通过pyplot函数快速绘图&#xff08;自…

GIC控制器(一)

目录 处理器工作模式 异常源 ​编辑寄存器组织结构 异常处理流程 CPSR寄存器 异常向量表 编写异常向量表 CP15协处理器 CP15 协处理器寄存器分组 协处理器指令 C0寄存器 C1寄存器 C12寄存器 C15寄存器 CBAR寄存器 Reset异常 前言&#xff1a; GIC&#xff08;G…

深入解析RS485通信:从原理到Linux驱动开发实践

深入解析RS485通信&#xff1a;从原理到Linux驱动开发实践在工业控制、智能建筑和物联网领域&#xff0c;RS485凭借其强大的抗干扰能力和多节点组网特性&#xff0c;成为长距离可靠通信的首选方案。本文将带您深入理解RS485的核心技术。一、RS485通信技术解析 1.1 RS485与RS232…

Linux系统常用性能分析运维命令

分类命令描述CPU性能分析相关命令mpstat -P ALL 5监控所有CPU的使用情况&#xff0c;间隔5秒后输出一组数据。用于查看是否出现某个CPU占满的情况CPU性能分析相关命令pidstat -u 5 1监控所有进程的CPU使用情况&#xff0c;用于查看是否出现某个进程CPU占用过高的问题CPU性能分析…

HTTP 压缩

介绍 压缩是提升网站性能的关键手段之一。对于某些类型的文件&#xff0c;最大可减少 70% 的大小&#xff0c;从而大幅降低带宽需求。随着时间的推移&#xff0c;压缩算法不断得到优化&#xff0c;新的高效算法也逐渐被客户端和服务器所支持。 在实际应用中&#xff0c;Web 开…

STM32之循迹避障模块TCRT5000红外反射传感器

目录 一、系统概述 二、TCRT5000红外反射传感器简介 2.1 基本概述 2.2 结构与工作原理 2.2.1 物理结构 2.2.2 工作流程 2.2.3 电路原理图 2.3 电气特性 2.4 模块接口说明 2.5 典型应用电路 2.6 实际应用注意事项 三、硬件设计 3.1 硬件组成 3.2 硬件连…

新能源汽车功率级测试自动化方案:从理论到实践的革命性突破

> 在800V高压平台普及与碳化硅半导体爆发的双轮驱动下,传统测试方法正经历颠覆性变革 “当我看到工程师手动记录测试数据时,就知道这个行业需要一场革命。”——某新能源车企测试总监的深夜感慨 ## 01 新能源汽车测试的痛点与变革 当新能源汽车的**电驱系统功率密度突…

【网络编程】事件驱动 reactor 式的服务器(EPOLL机制)

文章目录业务拆解事件驱动的 reactor总流程图C 代码实现准备工作编写头文件 reactor.h准备头文件准备宏定义声明三大模块函数和基础的内存变量长度定义全局变量定义 EPOLL 实例事件处理的函数与释放资源的函数注册服务器监听套接字的函数accept_cb 模块read_cb 模块send_cb 模块…

如何做好云服务器密码管理

一、设置强密码 强密码就像是给云服务器上了一把“超级锁”。专家建议&#xff0c;一个强密码应该包含大写字母、小写字母、数字和特殊字符&#xff0c;长度至少在 12 位以上。比如说&#xff0c;“Abc12345678”就比简单的“123456”要安全得多。有数据显示&#xff0c;简单密…

《新消费模式与消费者权益保护研讨会》课题研讨会在北京顺利召开

近期&#xff0c;《新消费模式与消费者权益保护研讨会》课题研讨会在北京召开。来自市场监管、政法、宏观管理等部门专家参会&#xff0c;聚焦《消费者权益保护法》《关于以新业态新模式引领新型消费加快发展的意见》等文件精神&#xff0c;探讨激发市场主体活力、促进新型消费…

Gradio全解13——MCP协议详解(6)——MCP服务器构建、测试与示例大全

Gradio全解13——MCP协议详解&#xff08;6&#xff09;——MCP服务器构建、测试与示例大全第13章 MCP协议详解13.6 MCP服务器构建、测试与示例大全13.6.1 开发MCP天气服务器1. 天气服务器概述2. 安装Node.js并设置环境3. 构建服务器13.6.2 安装Claude for Desktop1. 安装Claud…

Windows 11 24H2 专业版/家庭版安装教程(2025年6月更新版)- U盘启动盘制作+详细步骤

准备U盘启动盘​ 下载个叫「Rufus」的免费小工具&#xff08;百度搜就行&#xff09;。插入一个至少8GB的空U盘&#xff08;U盘会被清空&#xff0c;提前备份资料&#xff01;&#xff09;。打开Rufus&#xff0c;选你的U盘&#xff0c;ISO文件选你下载的那个 zh-cn_windows_1…

mac电脑wireshark快速实现http接口抓包

wireshark介绍 Wireshark 是一款功能强大的网络协议分析工具&#xff0c;可以用来抓取网络中的数据包&#xff0c;包括 HTTP 请求和响应。 wireshark安装 安装下载官网 https://www.wireshark.org/download.html&#xff0c;根据个人电脑环境下载安装wireshark使用 1配置网卡2选…

Softhub软件下载站实战开发(十二):软件管理编辑页面实现

文章目录 Softhub软件下载站实战开发&#xff08;十二&#xff09;&#xff1a;软件管理编辑页面实现✨功能概述 &#x1f4cb;编辑页面实现 &#x1f6e0;️1. 页面结构设计2. aieEditor集成 &#x1f31f;初始化配置编辑器功能 3. 大整数处理 &#x1f522;4. 封面图片上传 &…

微服务外联Feign调用:第三方API调用的负载均衡与容灾实战

01Feign 简介 Feign 是 Spring Cloud Netflix 中的 声明式 HTTP 客户端&#xff0c;它如同一位贴心的信使&#xff0c;帮我们化繁为简&#xff0c;让服务间的调用变得轻松又高效。 Feign 的核心优势在于&#xff1a;。 • 声明式调用&#xff1a;开发者只需定义接口和注解&a…

k8s pod调度基础

目录 一&#xff1a;replication controller和replicaset 1&#xff1a;replication controller replication controller的使用示例。 2&#xff1a;标签与标签选择器 &#xff08;1&#xff09;标签 &#xff08;2&#xff09;标签选择器 &#xff08;3&#xff09;标签…