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

Spring框架之策略模式 (Strategy Pattern)

策略模式(Strategy Pattern)详解

策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列算法,并将每种算法封装到独立的策略类中,使它们可以相互替换,从而使算法的变化独立于使用算法的客户端(即使用这些算法的代码)。通过策略模式,用户可以根据需要选择不同的算法,实现系统的 开放-关闭原则(Open/Closed Principle)

1. 策略模式的定义

1.1 什么是策略模式?

策略模式定义了一系列算法,将每个算法封装起来,并且使它们可以互相替换。策略模式让算法独立于使用它的客户端而变化。它的核心思想是:定义一组可互换的策略对象,将这些策略对象注入到上下文对象中,从而让上下文对象在运行时可以动态地更换不同的策略。

1.2 策略模式的特点
  • 封装变化:将算法封装在独立的类中,使得算法的修改不会影响使用算法的客户端。
  • 消除条件语句:避免在客户端代码中使用大量的 if-elseswitch-case 语句。
  • 提高扩展性:新增策略时,只需添加新的策略类,而无需修改现有代码。

2. 策略模式的结构

策略模式通常包含以下几个角色:

  1. 策略接口(Strategy)
    • 定义所有支持的算法的公共接口。
  2. 具体策略(ConcreteStrategy)
    • 实现策略接口的具体算法。
  3. 上下文(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. 策略模式的应用场景

策略模式适合以下场景:

  1. 多个类只在行为上有所不同
    • 当多个类的功能类似,仅在算法或行为上有所区别时,可以使用策略模式来封装这些行为。
  2. 消除条件语句
    • 当系统中有大量的 if-elseswitch-case 语句时,可以考虑使用策略模式来替代这些条件语句。
  3. 需要动态更改算法
    • 例如支付方式(信用卡、PayPal、比特币)、排序算法(快速排序、归并排序)、日志记录方式(文件、数据库、控制台)。
  4. 系统需要灵活扩展
    • 可以在不修改原有代码的情况下,轻松添加新的策略。

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. 策略模式的实际应用示例

  1. 支付系统
    • 支持多种支付方式(如支付宝、微信、信用卡、PayPal),用户可以根据需要选择不同的支付方式。
  2. 日志记录系统
    • 可以将日志记录到文件、数据库或控制台等不同的地方,日志策略可以根据配置动态切换。
  3. 数据压缩算法
    • 支持不同的数据压缩算法(如 ZIP、RAR、GZIP),用户可以选择不同的压缩策略。

8. 总结

策略模式是一个非常有用的设计模式,尤其是在需要根据不同的条件选择不同的算法时。通过将算法封装成独立的类,并将这些类抽象化为策略接口,可以有效地提高代码的复用性、可维护性和扩展性。

  • 优点:符合开闭原则、消除条件语句、提高代码复用性。
  • 缺点:增加类数量、客户端需要了解策略、策略间无法共享数据。
  • 适用场景:算法选择、支付方式、日志记录、多样化业务逻辑。

相关文章:

Spring框架之策略模式 (Strategy Pattern)

策略模式&#xff08;Strategy Pattern&#xff09;详解 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;用于定义一系列算法&#xff0c;并将每种算法封装到独立的策略类中&#xff0c;使它们可以相互替换&#xff0c;从而使算法的变化独…...

探索Google Earth Engine:利用MODIS数据和R语言进行2000-2021年遥感生态指数(RSEI)的时空趋势分析

前段时间,小编学习了在GEE上进行遥感生态指数(RSEI)的评估,非常头疼,但是实验了两周后,亲测有效,主要采用的是MODIS数据分析了2000-2021年中国内蒙古某地的RSEI时间序列分布状况,现在把学习的代码分享给大家。 1 GEE计算RSEI 1.1研究区域导入与初步定义 var sa = ee…...

多商户中英双语电商系统设计与开发 PHP+mysql

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

牵手App红娘专属1V1服务,打造贴心交友指导

对于年轻一代而言&#xff0c;婚恋方式已明显区别于传统&#xff0c;他们更倾向于直接、活泼的交流方式&#xff0c;享受着在轻松愉快的氛围中边玩边交友的乐趣。线上社交平台&#xff0c;尤其是那些基于兴趣构建的交友模式&#xff0c;正逐渐成为他们探索爱情、寻找共鸣的新舞…...

论文解析:边缘计算网络中资源共享的分布式协议(2区)

目录 论文解析:边缘计算网络中资源共享的分布式协议(2区) 核心内容: 核心创新点的原理与理论: 多跳边缘计算场景 一、边缘计算的基本概念 二、多跳边缘计算场景的含义 三、多跳边缘计算场景的应用 四、多跳边缘计算场景的优势 论文解析:协作边缘计算网络中资源共…...

Android Osmdroid + 天地图 (一)

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

浅谈:基于三维场景的视频融合方法

视频融合技术的出现可以追溯到 1996 年 , Paul Debevec等 提出了与视点相关的纹理混合方法 。 也就是说 &#xff0c; 现实的漫游效果不是从摄像机的角度来看 &#xff0c; 但其仍然存在很多困难 。基于三维场景的视频融合 &#xff0c; 因其直观等特效在视频监控等相关领域有着…...

PostgreSQL序列:创建、管理与高效应用指南

一、引言 在PostgreSQL中&#xff0c;序列&#xff08;Sequence&#xff09;是一种用于生成唯一标识符的数据库对象。它们常常被用于为主键字段提供连续且唯一的值&#xff0c;特别是在创建新记录时。序列提供了一种机制&#xff0c;能够确保每次调用都能返回一个唯一的值&…...

部署安装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&#xff08;自定义目录安装&#xff09; 1、创建自己的mysql-8.0&#xff0c;解压mysql安装包 tar -zxv…...

重要通知:Sedex 旧平台即将关闭

我们正在对 Sedex 平台进行一些重要更新&#xff0c;这些更新将更好地提升您的用户体验。 作为更新计划的⼀部分&#xff0c;我们将在 2025 年 2 ⽉关闭 Sedex Advance 平台&#xff08;即&#xff0c;Sedex 旧平台&#xff09;。旧平台的⼀些功能将转移到当前的平台上。这些改…...

Windows配置NTP时间同步

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

学Linux的第八天

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

2024IJCAI | MetalISP: 仅用1M参数的RAW到RGB高效映射模型

文章标题是&#xff1a;《MetaISP:Effcient RAW-to-sRGB Mappings with Merely 1M Parameters》 MetaISP收录于2024IJCAI&#xff0c;是新加坡国立大学&#xff08;Xinchao Wang为通讯作者&#xff09;和华为联合研发的新型ai-isp。 原文链接&#xff1a;MetaISP 【1】论文的…...

aws-athena查询语句总结

完全归于本人mysql语句小白&#xff0c;是一点也写不出来&#xff0c;故汇总到此 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 配置接口地址 文件地址&#xff1a;src\utils\apis.js //系统相关的接口 const SystemApis {sliderListUrl:apiHost"/system/slider/list/",//发送…...

react 中 useContext Hook 作用

useContext是一个用于在组件之间共享数据的重要钩子函数 一、跨组件数据共享 1. 简化多层级组件数据传递 例如&#xff1a;在一个具有多层级菜单结构的应用中&#xff0c;如果要将用户权限数据从根组件传递到最深层的菜单项组件&#xff0c;可能需要经过多个中间组件的 prop…...

【HarmonyOS】鸿蒙系统在租房项目中的项目实战(一)

从今天开始&#xff0c;博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”&#xff0c;对于刚接触这项技术的小伙伴在学习鸿蒙开发之前&#xff0c;有必要先了解一下鸿蒙&#xff0c;从你的角度来讲&#xff0c;你认为什么是鸿蒙呢&#xff1f;它出现的意义又是…...

前 K 个高频元素

前 K 个高频元素 ​ 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2]示例 2: 输入: nums [1], k 1 输出: [1]提示&#xff1a; 1 < nums.le…...

【ubuntu】Geogebra

Geogebra 几何作图工具 是一款跨平台的几何作图工具软件&#xff0c; 目前已经覆盖了&#xff0c; windows&#xff0c;android&#xff0c; mac, linux 等操作系统。 Ubuntu 现状 Ubuntu 自带应用市场 Ubuntu 自带应用市场目前只有 Geogebra 4.0 版本&#xff0c; 不能画立…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

数据库——redis

一、Redis 介绍 1. 概述 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的内存键值数据库系统&#xff0c;具有以下核心特点&#xff1a; 内存存储架构&#xff1a;数据主要存储在内存中&#xff0c;提供微秒级的读写响应 多数据结构支持&…...

【若依】框架项目部署笔记

参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作&#xff1a; 压缩包下载&#xff1a;http://download.redis.io/releases 1. 上传压缩包&#xff0c;并进入压缩包所在目录&#xff0c;解压到目标…...