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

【Java设计模式-4】策略模式,消灭if/else迷宫的利器

各位Java编程小伙伴们!今天咱们要一起探索一个超级厉害的Java设计模式——策略模式,它就像是一把神奇的魔法剑,专门用来斩断那些让我们代码变得乱糟糟的if/else语句迷宫!
在这里插入图片描述

一、if/else的烦恼

在编程的奇妙世界里,我们常常会遇到这样的情况:要根据不同的条件执行不同的操作,这时候,if/else语句就像我们最先想到的武器,冲上去就一顿猛操作。比如说,你正在开发一个电商系统。在计算商品价格的时候,根据不同的用户类型,有着不同的折扣策略。比如,普通用户可能没有折扣,会员用户打9折,VIP用户打8折。要是按照常规的写法,那代码可能就会是这样的:

public class PriceCalculator {public double calculatePrice(double originalPrice, String userType) {if ("普通用户".equals(userType)) {return originalPrice;} else if ("会员用户".equals(userType)) {return originalPrice * 0.9;} else if ("VIP用户".equals(userType)) {return originalPrice * 0.8;} else {throw new IllegalArgumentException("未知的用户类型");}}
}

看着这段代码,一开始可能觉得还行呀,不就几个if/else嘛。但随着我们用户类型和折扣规则越来越多,这个方法就会变得越来越臃肿。每次新增一种用户,都得在这个长长的if/else链里添加新的判断分支,这不仅让代码变得又长又难看,而且维护起来简直是噩梦。要是不小心改错了一个判断条件或者顺序,那可就会出现各种奇怪的错误。
而且,这种写法的代码可读性也越来越差,就好比走进了一个错综复杂的迷宫,别人(包括未来的自己)要看懂这段代码得费好大的劲儿,得在那一堆if/else里来回穿梭,试图搞清楚每个分支到底是干嘛的。这可不行呀,我们的代码应该像一本清晰易懂的故事书,而不是让人头疼的谜题集呢。

二、策略模式来救场啦!

这时候,策略模式就闪亮登场啦!它的核心思想呢,就是把不同的算法或者策略封装成一个个独立的类,然后让这些类可以相互替换,这样就可以根据不同的情况灵活地选择使用哪个策略啦。

咱们就用上面电商系统的例子来看看怎么用策略模式改写吧。

第一步:定义策略接口

首先,我们要定义一个折扣策略的接口,所有具体的折扣策略都要实现这个接口。

public interface DiscountStrategy {double calculateDiscount(double originalPrice);
}

这个接口里只有一个方法calculateDiscount,用来根据原价计算出折扣后的价格。

第二步:实现具体策略类

接下来,我们就为不同的用户类型分别创建具体的折扣策略类。

普通用户折扣策略类:

public class NormalUserDiscountStrategy implements DiscountStrategy {@Overridepublic double calculateDiscount(double originalPrice) {return originalPrice;}
}

对于普通用户,就是直接返回原价,没有折扣嘛。

会员用户折扣策略类:

public class MemberUserDiscountStrategy implements DiscountStrategy {@Overridepublic double calculateDiscount(double originalPrice) {return originalPrice * 0.9;}
}

会员用户就按照9折来计算。

VIP用户折扣策略类:

public class VIPUserDiscountStrategy implements DiscountStrategy {@Overridepublic double calculateDiscount(double originalPrice) {return originalPrice * 0.8;}
}

VIP用户则是8折优惠。

第三步:使用策略模式的上下文类

最后,我们还需要一个上下文类,这个类负责持有一个具体的折扣策略对象,并且提供一个方法来执行折扣计算。

public class PriceCalculatorContext {private DiscountStrategy discountStrategy;public PriceCalculatorContext(DiscountStrategy discountStrategy) {this.discountStrategy = discountStrategy;}public double calculatePrice(double originalPrice) {return discountStrategy.calculateDiscount(originalPrice);}
}

现在,我们再来看看怎么使用这些类来计算商品价格吧。

public class Main {public static void main(String[] args) {double originalPrice = 100;// 普通用户价格计算PriceCalculatorContext normalContext = new PriceCalculatorContext(new NormalUserDiscountStrategy());double normalPrice = normalContext.calculatePrice(originalPrice);System.out.println("普通用户价格:" + normalPrice);// 会员用户价格计算PriceCalculatorContext memberContext = new PriceCalculatorContext(new MemberUserDiscountStrategy());double memberPrice = memberContext.calculatePrice(originalPrice);System.out.println("会员用户价格:" + memberPrice);// VIP用户价格计算PriceCalculatorContext vipContext = new PriceCalculatorContext(new VIPUserDiscountStrategy());double vipPrice = vipContext.calculatePrice(originalPrice);System.out.println("VIP用户价格:" + vipPrice);}
}

这样一看,代码是不是清晰多啦?每个折扣策略都有自己独立的类,而且如果以后要增加新的用户类型或者修改折扣规则,只需要再创建一个新的策略类或者修改对应的策略类就可以了,完全不需要在那个乱糟糟的if/else语句里折腾啦。

三、策略模式的应用场景

其实我们在SpringBoot实际开发中策略模式经常用到,我一说你就有共鸣了,以下是一些用到常见的地方:

1. 数据源配置(DataSource)

在Spring Boot中,当配置多个数据源时会涉及到策略模式的应用。例如,你可能有一个主数据源用于核心业务操作,还有一个从数据源用于读取数据等场景。

  • 策略接口javax.sql.DataSource 接口可以看作是一种策略接口,它定义了获取数据库连接等相关操作的规范。不同的数据库驱动厂商(如MySQL、PostgreSQL等)实现这个接口来提供各自特定的数据源实现,这就是不同的“策略”。

  • 具体策略实现:像 com.mysql.cj.jdbc.MysqlDataSource (MySQL数据库的数据源实现)、org.postgresql.ds.PGDataSource(PostgreSQL数据库的数据源实现)等都是具体的策略类,它们根据各自数据库的特性来实现 DataSource 接口中规定的获取连接等操作。

  • 上下文使用:在SpringBoot应用中,当你在配置文件中指定了要使用的数据库类型及相关连接参数后,Spring会根据这些信息自动装配相应的数据源实现(即选择合适的策略)。例如,通过 spring.datasource.urlspring.datasource.username 等配置项,Spring会解析并装配对应的数据源,就如同在策略模式的上下文环境中根据具体情况选用合适的策略一样。

2. 消息队列集成(Message Queuing)

SpringBoot可以方便地与多种消息队列进行集成,如RabbitMQ、Kafka等,这里也用到了策略模式。

  • 策略接口:例如,org.springframework.amqp.core.AmqpTemplate (用于RabbitMQ的消息发送和接收操作的接口)和 org.springframework.kafka.core.KafkaTemplate(用于Kafka的消息发送和接收操作的接口)等类似接口可以看作是不同消息队列的策略接口,它们定义了各自与对应消息队列进行交互的操作规范。

  • 具体策略实现:像 org.springframework.amqp.rabbit.core.RabbitTemplate(RabbitMQ的具体实现)、org.springframework.kafka.core.KafkaTemplate(本身就是Kafka的具体实现)等都是不同的消息队列的具体策略类,它们根据各自消息队列的特性来实现相应接口规定的操作。

  • 上下文使用:在应用的配置文件中指定要集成的消息队列类型及相关参数(如 spring.rabbitmq.host 等对于RabbitMQ的配置,spring.kafka.bootstrap.servers 等对于Kafka的配置),Spring Boot会根据这些信息自动装配相应的消息队列实现(即选择合适的策略),并在需要进行消息发送、接收等操作的地方应用该策略。

这些只是SpringBoot中应用策略模式的一部分例子,实际上在很多涉及到多种可选方案、根据不同条件选择不同处理方式的场景下,都可能会运用到策略模式来使得代码更加清晰、可维护和可扩展。

四、总结

策略模式真的是一个非常实用的设计模式,帮我们把那些杂乱无章的if/else语句统统消灭掉,让我们的代码更加清晰、可维护、可扩展。以后在遇到类似根据不同情况选择不同算法或者行为的问题时,大家可别忘了试试策略模式哦。

好啦,今天关于策略模式的分享就到这里啦,希望小伙伴们都能在自己的代码世界里用好这个神奇的模式,写出更加优秀的程序哟!


上述内容只代表个人观点,不代表啥组织。本人致力于宣扬正能量,若因浏览出啥岔子,纯属无心之举,我马上就改正,可千万别上纲上线哈,愿大家开心每一天,peace & love~😜

相关文章:

【Java设计模式-4】策略模式,消灭if/else迷宫的利器

各位Java编程小伙伴们!今天咱们要一起探索一个超级厉害的Java设计模式——策略模式,它就像是一把神奇的魔法剑,专门用来斩断那些让我们代码变得乱糟糟的if/else语句迷宫! 一、if/else的烦恼 在编程的奇妙世界里,我们…...

citrix netscaler13.1 重写负载均衡响应头(基础版)

在 Citrix NetScaler 13.1 中,Rewrite Actions 用于对负载均衡响应进行修改,包括替换、删除和插入 HTTP 响应头。这些操作可以通过自定义策略来完成,帮助你根据需求调整请求内容。以下是三种常见的操作: 1. Replace (替换响应头)…...

【AI学习】地平线首席架构师苏箐关于自动驾驶的演讲

在地平线智驾科技畅想日上,地平线副总裁兼首席架构师苏箐(前华为智驾负责人)做了即兴演讲,以下是其演讲的主要内容: 对自动驾驶行业的看法 自动驾驶的难度与挑战:苏箐表示自动驾驶非常难,他做自…...

QILSTE H11-D212HRTCG/5M高亮红绿双色LED灯珠 发光二极管LED

型号:H11-D212HRTCG/5M,一款由QILSTE(HongKong)Technology Co., Ltd精心打造的高亮度红绿双色LED产品,其尺寸仅为2.01.251.1 mm,却蕴含着强大的光电特性。这款产品采用透明平面胶体封装,不仅外观…...

2️⃣java基础进阶——多线程、并发与线程池的基本使用

一、概念介绍 什么是线程,什么是进程,两者有什么关系? 进程是操作系统资源分配的独立单位;而线程是操作系统能够进行调度和分派的最小单位;线程包含于进程之中,是进程中的实际运作单位。 例如&#xff1a…...

RAG多路召回

什么是多路召回? 多路召回(Multi-Route Retrieval) 是指在信息检索系统中,为了提升检索的全面性和准确性,通过多条不同的检索路径或不同的检索策略来获取信息的技术。多路召回的核心思想是,单一的检索路径…...

复杂 C++ 项目堆栈保留以及 eBPF 性能分析

在构建和维护复杂的 C 项目时,性能优化和内存管理是至关重要的。当我们面对性能瓶颈或内存泄露时,可以使用eBPF(Extended Berkeley Packet Filter)和 BCC(BPF Compiler Collection)工具来分析。如我们在Red…...

网安——计算机网络基础

一、计算机网络概述 1、Internet网相关概念及发展 网络(Network)有若干结点(Node)和连接这些结点的链路(link)所组成,在网络中的结点可以是计算机、集线器、交换机或路由器等多个网络还可以通…...

ZCC1923替代BOS1921Piezo Haptic Driver with Digital Front End

FEATURES • High-Voltage Low Power Piezo Driver o Drive 100nF at 190VPP and 250Hz with 490mW o Drives Capacitive Loads up to 1000nF o Energy Recovery o Differential Output o Small Solution Footprint, QFN & WLCSP • Low Quiescent Current: SHUTDOWN; …...

Kutools for Excel 简体中文版 - 官方正版授权

Kutools for Excel 是一款超棒的 Excel 插件,就像给你的 Excel 加了个超能助手。它有 300 多种实用功能,现在还有 AI 帮忙,能把复杂的任务变简单,重复的事儿也能自动搞定,不管是新手还是老手都能用得顺手。有了它&…...

PostgreSQL和MySQL有什么区别?

一、数据存储与管理方面 数据类型支持 PostgreSQL: 提供了非常丰富的数据类型。除了基本的整数、浮点数、字符、日期等类型外,对复杂数据类型的支持很出色。例如,它原生支持数组(Array)类型,可以方便地存储…...

比较之舞,优雅演绎排序算法的智美篇章

大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 引言正文一、冒泡排序:数据海…...

C语言数据结构与算法(排序)详细版

大家好,欢迎来到“干货”小仓库!! 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!无人扶我青云志,我自踏雪至山巅!!&am…...

JAVA:利用 RabbitMQ 死信队列实现支付超时场景的技术指南

1、简述 在支付系统中,订单支付的超时自动撤销是一个非常常见的业务场景。通常用户未在规定时间内完成支付,系统会自动取消订单,释放相应的资源。本文将通过利用 RabbitMQ 的 死信队列(Dead Letter Queue, DLQ)来实现…...

pytest+request+yaml+allure搭建低编码调试门槛的接口自动化框架

接口自动化非常简单,大致分为以下几步: 准备入参调用接口拿到2中response,继续组装入参,调用下一个接口重复步骤3校验结果是否符合预期 一个优秀接口自动化框架的特点: 【编码门槛低】,又【能让新手学到…...

Elasticsearch实战指南:从入门到高效使用

Elasticsearch实战指南:从入门到高效使用 1. 引言:Elasticsearch是什么? Elasticsearch是一个分布式、RESTful风格的搜索和分析引擎,广泛应用于全文搜索、日志分析、实时数据分析等场景。它的核心特点包括: 高性能&…...

Open FPV VTX开源之嵌入式OSD配置

Open FPV VTX开源之嵌入式OSD配置 1. 源由2. 安装3. 配置步骤一:备份/etc/telemetry.conf步骤二:修改/etc/telemetry.conf步骤三:配置时区步骤四:重启摄像头 4. 实测5. 参考资料 1. 源由 穿越机模拟图传延迟通常在10ms左右。 最…...

2Hive表类型

2Hive表类型 1 Hive 数据类型2 Hive 内部表3 Hive 外部表4 Hive 分区表5 Hive 分桶表6 Hive 视图 1 Hive 数据类型 Hive的基本数据类型有:TINYINT,SAMLLINT,INT,BIGINT,BOOLEAN,FLOAT,DOUBLE&a…...

计算机网络之---公钥基础设施(PKI)

公钥基础设施 公钥基础设施(PKI,Public Key Infrastructure) 是一种用于管理公钥加密的系统架构,它通过结合硬件、软件、策略和标准来确保数字通信的安全性。PKI 提供了必要的框架,用于管理密钥对(包括公钥…...

EF Core执行原生SQL语句

目录 EFCore执行非查询原生SQL语句 为什么要写原生SQL语句 执行非查询SQL语句 有SQL注入漏洞 ExecuteSqlInterpolatedAsync 其他方法 执行实体相关查询原生SQL语句 FromSqlInterpolated 局限性 执行任意原生SQL查询语句 什么时候用ADO.NET 执行任意SQL Dapper 总…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

ESP32读取DHT11温湿度数据

芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...

今日科技热点速览

🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) ​遍历字符串​:通过外层循环逐一检查每个字符。​遇到 ? 时处理​: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: ​与…...