策略模式与简单工厂模式:终结if-else混乱,让代码更清爽
阅读建议
嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议:
- 本篇文章大概4500多字,预计阅读时间长需要5分钟。
- 本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章,建议收藏起来,方便时常学习与回顾,温故而知新。
- 创作不易,免费的点赞、关注,请走上一走,算是对博主一些鼓励,让我更有动力输出更多的干货内容。
前言
在软件开发过程中,我们常常面临着许多问题,其中之一就是如何有效地管理复杂的逻辑和流程。策略模式和工厂模式是两种非常实用的设计模式,可以帮助我们解决这些问题。本文将介绍策略模式和简单工厂模式的概念、实现和应用,并通过实例代码来演示它们的使用方法。
反面示例
需求描述
很多购物网站都有会员业务,不同等级的会员可以享受不同程度的优惠,不同类别的商品还有不同的打折优惠,这里假设只有会员优惠,会员等级有非会员、初级会员、中级会员、高级会员四个等级,其中非会员在支付的时候需要全额支付 ,初级会员可以享受9折优惠,中级会员可以享受8折优惠,高级会员可以享受6折优惠;如果需要写一个支付接口,需要怎么实现呢?
反面实现一
public Double actualPay(Double money) {String memberLevel = this.getMemberLevel();if ("初级".equals(memberLevel)) {money = money * 0.9;} else if ("中级".equals(memberLevel)) {money = money * 0.8;} else if ("高级".equals(memberLevel)) {money = money * 0.6;} else {money = money * 1;}return money;
}
需求变更
双十一举报大酬宾活动,如果购买商品总额超过300元,且小于400元,初级会员可以减免5元,中级会员可以减免8元,高级会员可以减免11元; 如果购买商品总额超过400元,且小于500元,初级会员可以减免10元,中级会员可以减免13元,高级会员可以减免16元; 如果购买商品总额超过500元,初级会员可以减免15元,中级会员可以减免18元,高级会员可以减免21元;
反面实现二
public Double actualPay(Double money) {String memberLevel = this.getMemberLevel();if ("初级".equals(memberLevel)) {money = money * 0.9;if (money > 300 && money <= 400) {money = money - 5;} else if (money > 400 && money <= 500) {money = money - 10;} else if (money > 500) {money = money - 15;}} else if ("中级".equals(memberLevel)) {money = money * 0.8;if (money > 300 && money <= 400) {money = money - 8;} else if (money > 400 && money <= 500) {money = money - 13;} else if (money > 500) {money = money - 18;}} else if ("高级".equals(memberLevel)) {money = money * 0.6;if (money > 300 && money <= 400) {money = money - 11;} else if (money > 400 && money <= 500) {money = money - 16;} else if (money > 500) {money = money - 21;}} else {money = money - 1;}return money;
}
反思总结
- 代码的可读性差。其他开发者在阅读此段代码时,需要花费一定的时间来理解每个条件。
- 维护性差。如果需求改变,例如增加一个新的折扣等级、新的活动内容,那么就需要修改这个if-else语句,可能会导致出错。
- 逻辑不清晰。这种if-else结构反复判断、嵌套很容易让人误解其意图,逻辑表现并不直观。
解决方案
策略模式与简单工厂模式
策略模式
策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式的主要目的是将算法的行为和环境分开,将一系列算法封装在策略类中,并在运行时根据客户端的需求选择相应的算法。策略模式适用于需要使用多种算法,且算法之间可以相互替换的情况。在策略模式中,算法的变化不会影响到使用算法的客户端。
简单工厂模式
简单工厂模式是一种属于创建型模式的设计模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式的核心是一个工厂类,它负责实现创建所有产品实例的内部逻辑。这个工厂类提供了一个或多个静态的工厂方法,根据参数的不同返回不同类的实例。这些被创建的实例通常都具有共同的父类。
实现原理
策略模式与简单工厂模式可以终结if-else混乱的工作原理是:通过封装算法和对象创建,使得代码更加模块化和可维护。
- 策略模式定义了一组算法,每个算法都可以独立地替换和修改,而不需要影响其他代码。通过使用策略模式,我们可以将算法从if-else语句中分离出来,将算法的封装和实现交由具体的策略类来处理。这样,如果需要添加新的算法或修改现有算法,我们只需要创建新的策略类或修改现有策略类,而不需要在主程序中添加if-else语句。
- 简单工厂模式提供了一种创建对象的接口,而不需要指定具体的类。通过使用简单工厂模式,我们可以将策略的创建和使用代码分离。具体来说,简单工厂模式可以根据输入参数或配置文件等信息来创建具体策略对象,并将具体策略对象的类型和使用方式交给调用方来处理。这样,我们可以在不修改原有代码的情况下,轻松地替换对象的具体实现。
实现步骤
1、定义抽象的支付策略接口:PayStrategy.java;
/*** 支付策略接口*/
public interface PayStrategy {/*** 实际支付金额计算* @param money*/Double compute(Double money);
}
2、定义具体的支付策略类:Level0Streategy.java、Level1Streategy.java、Level2Streategy.java、Level3Streategy.java
/*** 非会员计费策略*/
public class Level0Strategy implements PayStrategy{@Overridepublic Double compute(Double money) {System.out.println("非会员开始计费");return money;}
}
/*** 初级会员计费策略*/
public class Level1Strategy implements PayStrategy{@Overridepublic Double compute(Double money) {System.out.println("初级会员开始计费");return money*0.8;}
}
3、定义用于存储和传递策略的上下文:StreateContext.java
/*** 支付策略上下文*/
public class StrategyContent {private PayStrategy payStrategy;public StrategyContent(PayStrategy payStrategy) {this.payStrategy = payStrategy;}/*** 支付方法* @param money* @return*/public Double pay(Double money){return this.payStrategy.compute(money);}
}
4、定义策略工厂类,用于生产具体的策略:PayStreategyFactory.java
/*** 策略工厂*/
public class PayStrategyFactory {public static PayStrategy getStrategy(Member member){PayStrategy payStrategy;switch (member.getLevel()){case "初级":payStrategy=new Level1Strategy();break;case "中级":payStrategy=new Level2Strategy();break;case "高级":payStrategy=new Level3Strategy();break;default:payStrategy=new Level0Strategy();break;}return payStrategy;}
}
5、编写客户端:,模拟不同的用户进行支付:Test.java
public class ClientTest {public static void main(String[] args) {Member member = new Member("小明", "初级", 300.00);PayStrategy strategy = PayStrategyFactory.getStrategy(member);StrategyContent strategyContent = new StrategyContent(strategy);Double pay = strategyContent.pay(member.getPay());}
}
如何扩展
1、定义新的具体支付策略类来实现的抽象支付策略接口;
2、变更支付策略工厂的实现;
3、修改客户端业务;
反思总结
- 代码的可读性得到改善。具体的策略实现代替了原先的if分支判断,其他开发者在阅读此段代码时,通过不同的策略即可大概知道其逻辑。
- 维护性差。如果需求发生变更,只需要新增具体的策略实现即可,不会影响到其他已存在的策略,导致出错的概率大大降低。
- 通过过策略上下文,具体的支付金额计算与业务端解耦,逻辑更清晰。
是否还有其他解决方案?
- 策略模式与抽象工厂模式
- 策略模式与工厂方法模式
if-else真的干掉了吗?
当你以为一切都完美的解决的时候,实际上只是用一个方法解决了一个问题,然后又带来新的问题。新的问题是什么呢?
实际上在原先的if-else判断放到了策略工厂实现里了,面对新增的扩展需求,策略工厂的实现也是需要进行一定程度的修改的。如果实在不想修改,有没有解决方法?也有,那就是用抽象工厂代替简单工厂。是否有必要这样做,还需要结合具体的业务进行判断。
策略模式与简单工厂模式实际上并没有完全终止if-else的混乱,那么这么做还有意义吗?
当然有,业务端在调用时候,通过策略上下文类,实现了业务端调用逻辑与支付计算逻辑的解耦,由原来的乱糟糟一团,变成现在的几行代码,而且在后续的扩展上又提供了优秀灵活的扩展机制,一定程度上符合设计原则中的开闭原则,这就是意义。这里特别解释一下,一定程度上是指,需求的变更在实现上可以不影响原来的策略,但获取具体策略的逻辑需要一定程度修改。
相关文章:

策略模式与简单工厂模式:终结if-else混乱,让代码更清爽
阅读建议 嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议: 本篇文章大概4500多字,预计阅读时间长需要5分钟。本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章&#x…...

TCP三次握手过程
什么是TCP tcp是一个面向连接的、可靠的、基于字节流的传输层通信协议 面向连接:TCP连接是一对一的,不能实现一对多或多对一,TCP在通信前要首先建立连接,连接成功后才能开始进行通信可靠的:TCP连接要保证通信过程的可靠…...

04-配置远程仓库的SSH免密登陆
配置SSH免密登录 配置步骤 创建好的远程仓库也可以使用SSH的方式进行访问,但如果没有配置公钥会有警告 第一步: 删除用户家目录下的.ssh目录,如果没有该目录或者该目录下已经有密钥了就不用执行该操作 #进入当前用户的家目录,删除.ssh 目录 LayneLAPTOP-Layne MINGW64 ~ $ r…...

【中文编码】利用bert-base-chinese中的Tokenizer实现中文编码嵌入
最近接触文本处理,查询了一些资料,记录一下中文文本编码的处理方法吧。 先下载模型和词表:bert-base-chinese镜像下载 如下图示,下载好的以下文件均存放在 bert-base-chinese 文件夹下 1. 词编码嵌入简介 按我通俗的…...

一文解决msxml3.dll文件缺失问题,快速修复msxml3.dll
在了解问题之前,我们必须首先清楚msxml3.dll到底是什么。DLL(Dynamic Link Libraries)文件是Windows操作系统使用的一个重要组成部分,用于存储执行特定操作或任务的代码和数据。msxml3.dll为Windows系统提供处理XML文档的功能。如…...

《React 知识点》第一篇 大括号使用{}
简介 大括号 " {} "可以用于包裹JavaScript的表达式或语句。以便在jsx中动态生成内容。 插入变量与表达式 function expressionTest() {const name "变量测试";return (<p><div>{name}</div><div>表达式 210 {2 100}</div…...
kafka入门(二): 位移提交
位移提交: Kafka的每条消息都有唯一的 offset, 用来表示消息在分区中对应的位置。有的也称之为 “偏移量”。 消费者每次在 poll() 拉取消息,它要返回的是还没有消费过的消息集, 因此,需要记录上一次消费时的消费位…...
PG时间计算
PG数据库,时间计算使用场景总结 日期之差 --**获取秒差** SELECT round(date_part(epoch, TIMESTAMP 2019-05-05 12:11:20 - TIMESTAMP 2019-05-05 10:10:10)); --**获取分钟差** SELECT round(date_part(epoch, TIMESTAMP 2019-05-05 12:11:20 - TIMESTAMP 20…...

基于51单片机的交通灯_可调时间_夜间+紧急模式
51单片机交通灯 1 讲解视频:2 功能要求3 仿真图:4 原理图PCB5 实物图6 程序设计:7 设计报告8 资料清单(提供资料清单所有文件):设计资料下载链接: 51单片机简易交通灯_可调时间_夜间紧急 仿真代…...

网络通信原理,进制转化总结
来源,做个笔记,讲的还蛮清楚通信原理-2.5 数据封装与传输05_哔哩哔哩_bilibili ip地址范围...

西南科技大学(数据结构A)期末自测练习三
一、填空题(每空1分,共10分) 1、为解决计算机主机与打印机之间速度不匹配的问题,通常设置一个打印数据缓冲区。主机将要输出的数据依次写入缓冲区,打印机则依次从缓冲区中取出数据,则该换缓冲区的逻辑结构…...

【halcon】裁剪
前言 目前我遇到的裁剪相关的函数都是以clip打头的函数。一共4个: clip_end_points_contours_xldclip_contours_xldclip_regionclip_region_rel 前面两个是对轮廓的裁剪。 后面是对区域的裁剪。 裁剪轮廓的两端 clip_end_points_contours_xld 用于实现裁剪XLD…...

vue+less+style-resources-loader 配置全局颜色变量
全局统一样式后,可配置vue.config.js实现全局颜色变量,方便在编写时使用统一风格的色彩 一、新建global.less 二、下载安装style-resources-loader npm i style-resources-loader --save-dev三、在vue.config.js中进行配置 module.exports {pluginOpt…...

第二次量子化
专栏目录: 高质量文章导航-持续更新中 前置复盘: 玻色子和费米子: 首先,我们希望把描述单粒子态的量子力学推广到全同多粒子体系。我们的做法是从单粒子态的希尔伯特空间(Hilbert Space)出发,构造全同多粒子态的态空间——福克空间(Fock Space),它实际上就是无穷个…...

(三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言Q1:卷积网络和传统网络的区别Q2:卷积神经网络的架构Q3:卷积神经网络中的参数共享,也是比传统网络的优势所在4、 具体的实现代码网络搭建…...

【代码】多种调度模式下的光储电站经济性最优 储能容量配置分析matlab/yalmip
程序名称:多种调度模式下的光储电站经济性最优储能容量配置分析 实现平台:matlab-yalmip-cplex/gurobi 代码简介:代码主要做的是一个光储电站经济最优储能容量配置的问题,对光储电站中储能的容量进行优化,以实现经济…...

深度学习今年来经典模型优缺点总结,包括卷积、循环卷积、Transformer、LSTM、GANs等
文章目录 1、卷积神经网络(Convolutional Neural Networks,CNN)1.1 优点1.2 缺点1.3 应用场景1.4 网络图 2、循环神经网络(Recurrent Neural Networks,RNNs)2.1 优点2.2 缺点2.3 应用场景2.4 网络图 3、长短…...

ChatGPT成为“帮凶”:生成虚假数据集支持未知科学假设
ChatGPT 自发布以来,就成为了大家的好帮手,学生党和打工人更是每天都离不开。 然而这次好帮手 ChatGPT 却帮过头了,莫名奇妙的成为了“帮凶”,一位研究人员利用 ChatGPT 创建了虚假的数据集,用来支持未知的科学假设。…...
c#利用Forms.Timer定时检测Tcp连接状态
目的:本地创建客户端连接服务器端,如果连接正常显示连接正常如果连接异常显示连接异常。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.T…...
空间注意力:改变我们理解图像的方式
空间注意力:改变我们理解图像的方式 欢迎来到深度学习和计算机视觉的新时代,在这里,空间注意力机制正改变着我们理解和处理图像的方式。本文将深入探讨空间注意力的概念,它如何工作,以及为什么它在现代图像处理技术中…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...