Spring框架之策略模式 (Strategy Pattern)
策略模式(Strategy Pattern)详解
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列算法,并将每种算法封装到独立的策略类中,使它们可以相互替换,从而使算法的变化独立于使用算法的客户端(即使用这些算法的代码)。通过策略模式,用户可以根据需要选择不同的算法,实现系统的 开放-关闭原则(Open/Closed Principle)。
1. 策略模式的定义
1.1 什么是策略模式?
策略模式定义了一系列算法,将每个算法封装起来,并且使它们可以互相替换。策略模式让算法独立于使用它的客户端而变化。它的核心思想是:定义一组可互换的策略对象,将这些策略对象注入到上下文对象中,从而让上下文对象在运行时可以动态地更换不同的策略。
1.2 策略模式的特点
- 封装变化:将算法封装在独立的类中,使得算法的修改不会影响使用算法的客户端。
- 消除条件语句:避免在客户端代码中使用大量的
if-else
或switch-case
语句。 - 提高扩展性:新增策略时,只需添加新的策略类,而无需修改现有代码。
2. 策略模式的结构
策略模式通常包含以下几个角色:
- 策略接口(Strategy):
- 定义所有支持的算法的公共接口。
- 具体策略(ConcreteStrategy):
- 实现策略接口的具体算法。
- 上下文(Context):
- 持有策略接口的引用,用于调用具体的策略方法。
类图
+-----------------+
| Strategy |<---------------------+
|-----------------| |
| + algorithm() | |
+-----------------+ |^ || |
+-----------------+ +-------------------+
| ConcreteStrategyA | | ConcreteStrategyB |
|-------------------| |--------------------|
| + algorithm() | | + algorithm() |
+-------------------+ +--------------------+^|
+---------------------+
| Context |
|---------------------|
| - strategy: Strategy|
| + setStrategy() |
| + executeAlgorithm()|
+---------------------+
3. 策略模式的实现
为了更好地理解策略模式,我们使用一个简单的示例来演示其工作原理。假设我们要开发一个应用程序,用于计算商品的促销折扣。不同的促销活动有不同的折扣计算策略。
3.1 Java 示例代码
// 策略接口
interface DiscountStrategy {double calculateDiscount(double price);
}// 具体策略类:圣诞节促销
class ChristmasDiscount implements DiscountStrategy {@Overridepublic double calculateDiscount(double price) {System.out.println("使用圣诞节促销折扣");return price * 0.9; // 10% 折扣}
}// 具体策略类:新年促销
class NewYearDiscount implements DiscountStrategy {@Overridepublic double calculateDiscount(double price) {System.out.println("使用新年促销折扣");return price * 0.8; // 20% 折扣}
}// 具体策略类:无折扣
class NoDiscount implements DiscountStrategy {@Overridepublic double calculateDiscount(double price) {System.out.println("没有折扣");return price;}
}// 上下文类
class ShoppingCart {private DiscountStrategy discountStrategy;// 设置策略public void setDiscountStrategy(DiscountStrategy discountStrategy) {this.discountStrategy = discountStrategy;}// 计算最终价格public double calculateFinalPrice(double price) {return discountStrategy.calculateDiscount(price);}
}// 测试客户端
public class StrategyPatternDemo {public static void main(String[] args) {ShoppingCart cart = new ShoppingCart();// 使用圣诞节折扣cart.setDiscountStrategy(new ChristmasDiscount());System.out.println("最终价格: " + cart.calculateFinalPrice(100.0));// 使用新年折扣cart.setDiscountStrategy(new NewYearDiscount());System.out.println("最终价格: " + cart.calculateFinalPrice(100.0));// 使用无折扣cart.setDiscountStrategy(new NoDiscount());System.out.println("最终价格: " + cart.calculateFinalPrice(100.0));}
}
输出结果:
使用圣诞节促销折扣
最终价格: 90.0
使用新年促销折扣
最终价格: 80.0
没有折扣
最终价格: 100.0
4. 策略模式的应用场景
策略模式适合以下场景:
- 多个类只在行为上有所不同:
- 当多个类的功能类似,仅在算法或行为上有所区别时,可以使用策略模式来封装这些行为。
- 消除条件语句:
- 当系统中有大量的
if-else
或switch-case
语句时,可以考虑使用策略模式来替代这些条件语句。
- 当系统中有大量的
- 需要动态更改算法:
- 例如支付方式(信用卡、PayPal、比特币)、排序算法(快速排序、归并排序)、日志记录方式(文件、数据库、控制台)。
- 系统需要灵活扩展:
- 可以在不修改原有代码的情况下,轻松添加新的策略。
5. 策略模式的优缺点
5.1 优点
- 符合开闭原则:可以在不修改原有代码的情况下扩展新的策略。
- 避免使用复杂的条件判断:通过策略的多态性来消除条件语句,使代码更清晰、更易维护。
- 提高代码的复用性:将每个策略封装到独立的类中,使其可以被多个上下文重用。
5.2 缺点
- 增加类的数量:每个策略都需要定义一个类,导致类的数量增加,可能会使系统变得复杂。
- 客户端必须知道所有的策略:客户端需要了解所有可用的策略,以便在运行时选择合适的策略。
- 策略之间无法共享数据:策略类是相互独立的,无法直接共享数据,可能导致重复代码。
6. 策略模式的扩展
6.1 结合工厂模式(Factory Pattern)
策略模式可以与工厂模式结合使用,通过工厂类动态创建策略对象,减少客户端对策略类的直接依赖。
6.2 结合依赖注入(Dependency Injection)
在实际开发中,策略模式常与依赖注入结合使用,将策略对象通过构造函数或方法参数注入到上下文中。
6.3 Java 8 Lambda 表达式的简化
在 Java 8 中,可以使用 Lambda 表达式来简化策略模式的实现:
import java.util.function.Function;public class StrategyPatternWithLambda {public static void main(String[] args) {Function<Double, Double> christmasDiscount = price -> price * 0.9;Function<Double, Double> newYearDiscount = price -> price * 0.8;Function<Double, Double> noDiscount = price -> price;double price = 100.0;System.out.println("圣诞节折扣: " + christmasDiscount.apply(price));System.out.println("新年折扣: " + newYearDiscount.apply(price));System.out.println("无折扣: " + noDiscount.apply(price));}
}
7. 策略模式的实际应用示例
- 支付系统:
- 支持多种支付方式(如支付宝、微信、信用卡、PayPal),用户可以根据需要选择不同的支付方式。
- 日志记录系统:
- 可以将日志记录到文件、数据库或控制台等不同的地方,日志策略可以根据配置动态切换。
- 数据压缩算法:
- 支持不同的数据压缩算法(如 ZIP、RAR、GZIP),用户可以选择不同的压缩策略。
8. 总结
策略模式是一个非常有用的设计模式,尤其是在需要根据不同的条件选择不同的算法时。通过将算法封装成独立的类,并将这些类抽象化为策略接口,可以有效地提高代码的复用性、可维护性和扩展性。
- 优点:符合开闭原则、消除条件语句、提高代码复用性。
- 缺点:增加类数量、客户端需要了解策略、策略间无法共享数据。
- 适用场景:算法选择、支付方式、日志记录、多样化业务逻辑。
相关文章:
Spring框架之策略模式 (Strategy Pattern)
策略模式(Strategy Pattern)详解 策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列算法,并将每种算法封装到独立的策略类中,使它们可以相互替换,从而使算法的变化独…...
探索Google Earth Engine:利用MODIS数据和R语言进行2000-2021年遥感生态指数(RSEI)的时空趋势分析
前段时间,小编学习了在GEE上进行遥感生态指数(RSEI)的评估,非常头疼,但是实验了两周后,亲测有效,主要采用的是MODIS数据分析了2000-2021年中国内蒙古某地的RSEI时间序列分布状况,现在把学习的代码分享给大家。 1 GEE计算RSEI 1.1研究区域导入与初步定义 var sa = ee…...

多商户中英双语电商系统设计与开发 PHP+mysql
随着全球电商市场的扩展,多商户平台成为了越来越多商家参与全球贸易的重要方式。为了适应不同语言用户的需求,尤其是中英双语用户的需求,设计一个支持中英双语的电商系统显得尤为重要。本文将重点探讨如何设计一个多商户中英双语电商系统&…...

牵手App红娘专属1V1服务,打造贴心交友指导
对于年轻一代而言,婚恋方式已明显区别于传统,他们更倾向于直接、活泼的交流方式,享受着在轻松愉快的氛围中边玩边交友的乐趣。线上社交平台,尤其是那些基于兴趣构建的交友模式,正逐渐成为他们探索爱情、寻找共鸣的新舞…...
论文解析:边缘计算网络中资源共享的分布式协议(2区)
目录 论文解析:边缘计算网络中资源共享的分布式协议(2区) 核心内容: 核心创新点的原理与理论: 多跳边缘计算场景 一、边缘计算的基本概念 二、多跳边缘计算场景的含义 三、多跳边缘计算场景的应用 四、多跳边缘计算场景的优势 论文解析:协作边缘计算网络中资源共…...

Android Osmdroid + 天地图 (一)
Osmdroid 天地图 前言正文一、配置build.gradle二、配置AndroidManifest.xml三、获取天地图的API Key① 获取开发版SHA1② 获取发布版SHA1 四、请求权限五、显示地图六、源码 前言 Osmdroid是一款完全开源的地图基本操作SDK,我们可以通过这个SDK去加一些地图API&am…...

浅谈:基于三维场景的视频融合方法
视频融合技术的出现可以追溯到 1996 年 , Paul Debevec等 提出了与视点相关的纹理混合方法 。 也就是说 , 现实的漫游效果不是从摄像机的角度来看 , 但其仍然存在很多困难 。基于三维场景的视频融合 , 因其直观等特效在视频监控等相关领域有着…...
PostgreSQL序列:创建、管理与高效应用指南
一、引言 在PostgreSQL中,序列(Sequence)是一种用于生成唯一标识符的数据库对象。它们常常被用于为主键字段提供连续且唯一的值,特别是在创建新记录时。序列提供了一种机制,能够确保每次调用都能返回一个唯一的值&…...
部署安装jdk8\redis\mysql8\nginx
安装jdk8 linux安装jdk8详细步骤_linux jdk8安装-CSDN博客 安装redis 安装redis 后台启动命令 cd /ra/redis-6.0.0/src ./redis-server --daemonize yes安装mysql8.0(自定义目录安装) 1、创建自己的mysql-8.0,解压mysql安装包 tar -zxv…...
重要通知:Sedex 旧平台即将关闭
我们正在对 Sedex 平台进行一些重要更新,这些更新将更好地提升您的用户体验。 作为更新计划的⼀部分,我们将在 2025 年 2 ⽉关闭 Sedex Advance 平台(即,Sedex 旧平台)。旧平台的⼀些功能将转移到当前的平台上。这些改…...

Windows配置NTP时间同步
Windows下实现NTP时间同步 1、Windows时间服务(W32Time)2、Windows 时间同步的工作原理3、配置和管理 Windows 时间同步3.1 命令行工具:w32tm3.2 控制面板中的设置 4. 高级设置(Windows Server 环境)5.调整时间同步的间隔5.1 通过组策略调整时…...

学Linux的第八天
目录 管理进程 概念 程序、进程、线程 进程分类 进程前后台调用 查看进程 ps命令 unix 风格 bsd风格 GNU风格 top命令 格式 统计信息区 进程信息区:显示了每个进程的运行状态 kill命令 作用 格式 管理进程 概念 程序、进程、线程 程序&#x…...

2024IJCAI | MetalISP: 仅用1M参数的RAW到RGB高效映射模型
文章标题是:《MetaISP:Effcient RAW-to-sRGB Mappings with Merely 1M Parameters》 MetaISP收录于2024IJCAI,是新加坡国立大学(Xinchao Wang为通讯作者)和华为联合研发的新型ai-isp。 原文链接:MetaISP 【1】论文的…...
aws-athena查询语句总结
完全归于本人mysql语句小白,是一点也写不出来,故汇总到此 1. cloudtrail ## 查询事件排序 SELECT eventname,eventtime,count(eventname) as num FROM your_athena_tablename where eventtime between 2024-11-10 and 2024-11-11 group by eventname…...
电信网关配置管理后台 upload_channels.php 任意文件上传漏洞复现
0x01 产品描述: 电信网关配置管理后台是用于管理和配置电信网关的设备,提供了一系列功能来帮助用户监控和管理网络设备。以下是电信网关配置管理后台的主要功能和操作方法。0x02 漏洞描述: 电信网关配置管理系统/bak_manager/upload_channels.php 接口存在文件上传…...

Vue全栈开发旅游网项目(11)-用户管理前端接口联调
联调基本步骤 1.阅读接口文档 2.配置接口地址 3.使用axios获取数据 4.将数据设置到模型层 1.发送验证码联调 1.1 配置接口地址 文件地址:src\utils\apis.js //系统相关的接口 const SystemApis {sliderListUrl:apiHost"/system/slider/list/",//发送…...
react 中 useContext Hook 作用
useContext是一个用于在组件之间共享数据的重要钩子函数 一、跨组件数据共享 1. 简化多层级组件数据传递 例如:在一个具有多层级菜单结构的应用中,如果要将用户权限数据从根组件传递到最深层的菜单项组件,可能需要经过多个中间组件的 prop…...

【HarmonyOS】鸿蒙系统在租房项目中的项目实战(一)
从今天开始,博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”,对于刚接触这项技术的小伙伴在学习鸿蒙开发之前,有必要先了解一下鸿蒙,从你的角度来讲,你认为什么是鸿蒙呢?它出现的意义又是…...
前 K 个高频元素
前 K 个高频元素 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2]示例 2: 输入: nums [1], k 1 输出: [1]提示: 1 < nums.le…...

【ubuntu】Geogebra
Geogebra 几何作图工具 是一款跨平台的几何作图工具软件, 目前已经覆盖了, windows,android, mac, linux 等操作系统。 Ubuntu 现状 Ubuntu 自带应用市场 Ubuntu 自带应用市场目前只有 Geogebra 4.0 版本, 不能画立…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...

Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...