当前位置: 首页 > 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 总…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如&#xff1a…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

Vue 模板语句的数据来源

&#x1f9e9; Vue 模板语句的数据来源&#xff1a;全方位解析 Vue 模板&#xff08;<template> 部分&#xff09;中的表达式、指令绑定&#xff08;如 v-bind, v-on&#xff09;和插值&#xff08;{{ }}&#xff09;都在一个特定的作用域内求值。这个作用域由当前 组件…...

WEB3全栈开发——面试专业技能点P7前端与链上集成

一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染&#xff08;SSR&#xff09;与静态网站生成&#xff08;SSG&#xff09; 框架&#xff0c;由 Vercel 开发。它简化了构建生产级 React 应用的过程&#xff0c;并内置了很多特性&#xff1a; ✅ 文件系…...

ui框架-文件列表展示

ui框架-文件列表展示 介绍 UI框架的文件列表展示组件&#xff0c;可以展示文件夹&#xff0c;支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项&#xff0c;适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...

基于 HTTP 的单向流式通信协议SSE详解

SSE&#xff08;Server-Sent Events&#xff09;详解 &#x1f9e0; 什么是 SSE&#xff1f; SSE&#xff08;Server-Sent Events&#xff09; 是 HTML5 标准中定义的一种通信机制&#xff0c;它允许服务器主动将事件推送给客户端&#xff08;浏览器&#xff09;。与传统的 H…...

MyBatis-Plus 常用条件构造方法

1.常用条件方法 方法 说明eq等于 ne不等于 <>gt大于 >ge大于等于 >lt小于 <le小于等于 <betweenBETWEEN 值1 AND 值2notBetweenNOT BETWEEN 值1 AND 值2likeLIKE %值%notLikeNOT LIKE %值%likeLeftLIKE %值likeRightLIKE 值%isNull字段 IS NULLisNotNull字段…...

多模态大语言模型arxiv论文略读(112)

Assessing Modality Bias in Video Question Answering Benchmarks with Multimodal Large Language Models ➡️ 论文标题&#xff1a;Assessing Modality Bias in Video Question Answering Benchmarks with Multimodal Large Language Models ➡️ 论文作者&#xff1a;Jea…...