当前位置: 首页 > 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; 不能画立…...

vue2和vue3的区别详解

vue2 VS vue3 对比vue2vue3配置脚手架cmd命令行可视化方式创建脚⼿架组件通信props、$emit、provide、$arrts、EventBus等props、$emit、provide、inject、arrts等数据监听watch,computedwatch,watchEffect,computed双向绑定Object.definePropertyProxyAPI⽣命周期四个阶段befo…...

一文读懂LEED绿建

LEED绿建&#xff0c;即获得LEED&#xff08;Leadership in Energy and Environmental Design&#xff09;认证的建筑&#xff0c;是一个旨在提高建筑环境性能和健康性能的评估体系。以下是对LEED绿建的详细解读&#xff1a; 一、LEED体系概述 定义&#xff1a;LEED是由美国绿…...

git上feature合并到development分支

git上从development分支拉了一个feature分支开发新内容&#xff0c;development也有新内容在开发&#xff0c;feature分支内容开发完毕后&#xff0c;如何合并feature分支新内容到development分支&#xff0c;要确保不会覆盖development分支的新内容 以下是将 feature 分支的新…...

NVR录像机汇聚管理EasyNVR多品牌NVR管理工具/设备:大华IPC摄像头局域网访问异常解决办法

在当今社会&#xff0c;安全监控已成为各类场所不可或缺的一部分。无论是家庭、学校、商业场所还是公共场所&#xff0c;安全监控设备都扮演着至关重要的角色。在众多监控品牌中&#xff0c;大华IPC摄像头凭借其高清画质、强大功能和卓越稳定性&#xff0c;赢得了市场的广泛认可…...

校园二手交易网站毕业设计基于SpringBootSSM框架

目录 一、引言 二、需求分析 2.1用户需求分析 2.1.1学生用户 2.1.2管理员 2.2系统功能需求 2.3系统非功能需求 ‌2.4技术需求 ‌2.4.1 技术选择 ‌2.4.2系统架构‌ 三、详细设计 3.1系统架构设计‌ ‌3.2前端设计‌ ‌3.3后端设计‌ ‌3.4数据库设计‌ 本文介绍…...

基于大语言模型意图识别和实体提取功能;具体ZK数值例子:加密货币交易验证;

目录 基于大语言模型意图识别和实体提取功能 案例背景 零知识证明过程 具体例子 具体举例(简化) 具体ZK数值例子:加密货币交易验证 定义多项式 承诺 挑战 证明构造 证明验证 结论 zkLLM Zero Knowledge Proofs for Large Language Models 在大模型验证过程中处…...

论文笔记 SuDORMRF:EFFICIENT NETWORKS FOR UNIVERSAL AUDIO SOURCE SEPARATION

SUDORMRF: EFFICIENT NETWORKS FOR UNIVERSAL AUDIO SOURCE SEPARATION 人的精神寄托可以是音乐&#xff0c;可以是书籍&#xff0c;可以是运动&#xff0c;可以是工作&#xff0c;可以是山川湖海&#xff0c;唯独不可以是人。 Depthwise Separable Convolution 深度分离卷积&a…...

机器学习系列----KNN分类

目录 前言 一.KNN算法的基本原理 二.KNN分类的实现 三.总结 前言 在机器学习领域&#xff0c;K近邻算法&#xff08;K-Nearest Neighbors, KNN&#xff09;是一种非常直观且常用的分类算法。它是一种基于实例的学习方法&#xff0c;也被称为懒学习&#xff08;Lazy Learnin…...

贪心算法day 06

1.最长回文串 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;计算每个字符个数如果是偶数个那么肯定可以组成回文串&#xff0c;如果是奇数个就会有一个无法组成回文串&#xff0c;但是在最中间还是可以有一个不是成队的字符这个字符就从多的奇…...

HTML之列表学习记录

练习题&#xff1a; 图所示为一个问卷调查网页&#xff0c;请制作出来。要求&#xff1a;大标题用h1标签&#xff1b;小题目用h3标签&#xff1b;前两个问题使用有序列表&#xff1b;最后一个问题使用无序列表。 代码&#xff1a; <!DOCTYPE html> <html> <he…...