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

策略模式与简单工厂模式:终结if-else混乱,让代码更清爽

阅读建议

嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议:

  1. 本篇文章大概4500多字,预计阅读时间长需要5分钟。
  2. 本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章,建议收藏起来,方便时常学习与回顾,温故而知新。
  3. 创作不易,免费的点赞、关注,请走上一走,算是对博主一些鼓励,让我更有动力输出更多的干货内容。

前言

在软件开发过程中,我们常常面临着许多问题,其中之一就是如何有效地管理复杂的逻辑和流程。策略模式和工厂模式是两种非常实用的设计模式,可以帮助我们解决这些问题。本文将介绍策略模式和简单工厂模式的概念、实现和应用,并通过实例代码来演示它们的使用方法。

反面示例

需求描述

很多购物网站都有会员业务,不同等级的会员可以享受不同程度的优惠,不同类别的商品还有不同的打折优惠,这里假设只有会员优惠,会员等级有非会员、初级会员、中级会员、高级会员四个等级,其中非会员在支付的时候需要全额支付 ,初级会员可以享受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;
}

反思总结

  1. 代码的可读性差。其他开发者在阅读此段代码时,需要花费一定的时间来理解每个条件。
  2. 维护性差。如果需求改变,例如增加一个新的折扣等级、新的活动内容,那么就需要修改这个if-else语句,可能会导致出错。
  3. 逻辑不清晰。这种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、修改客户端业务;

反思总结

  1. 代码的可读性得到改善。具体的策略实现代替了原先的if分支判断,其他开发者在阅读此段代码时,通过不同的策略即可大概知道其逻辑。
  2. 维护性差。如果需求发生变更,只需要新增具体的策略实现即可,不会影响到其他已存在的策略,导致出错的概率大大降低。
  3. 通过过策略上下文,具体的支付金额计算与业务端解耦,逻辑更清晰。

是否还有其他解决方案?

  • 策略模式与抽象工厂模式
  • 策略模式与工厂方法模式

if-else真的干掉了吗?

当你以为一切都完美的解决的时候,实际上只是用一个方法解决了一个问题,然后又带来新的问题。新的问题是什么呢?

实际上在原先的if-else判断放到了策略工厂实现里了,面对新增的扩展需求,策略工厂的实现也是需要进行一定程度的修改的。如果实在不想修改,有没有解决方法?也有,那就是用抽象工厂代替简单工厂。是否有必要这样做,还需要结合具体的业务进行判断。

策略模式与简单工厂模式实际上并没有完全终止if-else的混乱,那么这么做还有意义吗?

当然有,业务端在调用时候,通过策略上下文类,实现了业务端调用逻辑与支付计算逻辑的解耦,由原来的乱糟糟一团,变成现在的几行代码,而且在后续的扩展上又提供了优秀灵活的扩展机制,一定程度上符合设计原则中的开闭原则,这就是意义。这里特别解释一下,一定程度上是指,需求的变更在实现上可以不影响原来的策略,但获取具体策略的逻辑需要一定程度修改。

相关文章:

策略模式与简单工厂模式:终结if-else混乱,让代码更清爽

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概4500多字&#xff0c;预计阅读时间长需要5分钟。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&#x…...

TCP三次握手过程

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

04-配置远程仓库的SSH免密登陆

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

【中文编码】利用bert-base-chinese中的Tokenizer实现中文编码嵌入

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

一文解决msxml3.dll文件缺失问题,快速修复msxml3.dll

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

《React 知识点》第一篇 大括号使用{}

简介 大括号 " {} "可以用于包裹JavaScript的表达式或语句。以便在jsx中动态生成内容。 插入变量与表达式 function expressionTest() {const name "变量测试";return (<p><div>{name}</div><div>表达式 210 {2 100}</div…...

kafka入门(二): 位移提交

位移提交&#xff1a; Kafka的每条消息都有唯一的 offset&#xff0c; 用来表示消息在分区中对应的位置。有的也称之为 “偏移量”。 消费者每次在 poll() 拉取消息&#xff0c;它要返回的是还没有消费过的消息集&#xff0c; 因此&#xff0c;需要记录上一次消费时的消费位…...

PG时间计算

PG数据库&#xff0c;时间计算使用场景总结 日期之差 --**获取秒差** 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 讲解视频&#xff1a;2 功能要求3 仿真图&#xff1a;4 原理图PCB5 实物图6 程序设计&#xff1a;7 设计报告8 资料清单&#xff08;提供资料清单所有文件&#xff09;&#xff1a;设计资料下载链接&#xff1a; 51单片机简易交通灯_可调时间_夜间紧急 仿真代…...

网络通信原理,进制转化总结

来源&#xff0c;做个笔记&#xff0c;讲的还蛮清楚通信原理-2.5 数据封装与传输05_哔哩哔哩_bilibili ip地址范围...

西南科技大学(数据结构A)期末自测练习三

一、填空题&#xff08;每空1分&#xff0c;共10分&#xff09; 1、为解决计算机主机与打印机之间速度不匹配的问题&#xff0c;通常设置一个打印数据缓冲区。主机将要输出的数据依次写入缓冲区&#xff0c;打印机则依次从缓冲区中取出数据&#xff0c;则该换缓冲区的逻辑结构…...

【halcon】裁剪

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

vue+less+style-resources-loader 配置全局颜色变量

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

第二次量子化

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

(三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言Q1&#xff1a;卷积网络和传统网络的区别Q2:卷积神经网络的架构Q3:卷积神经网络中的参数共享&#xff0c;也是比传统网络的优势所在4、 具体的实现代码网络搭建…...

【代码】多种调度模式下的光储电站经济性最优 储能容量配置分析matlab/yalmip

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

深度学习今年来经典模型优缺点总结,包括卷积、循环卷积、Transformer、LSTM、GANs等

文章目录 1、卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;CNN&#xff09;1.1 优点1.2 缺点1.3 应用场景1.4 网络图 2、循环神经网络&#xff08;Recurrent Neural Networks&#xff0c;RNNs&#xff09;2.1 优点2.2 缺点2.3 应用场景2.4 网络图 3、长短…...

ChatGPT成为“帮凶”:生成虚假数据集支持未知科学假设

ChatGPT 自发布以来&#xff0c;就成为了大家的好帮手&#xff0c;学生党和打工人更是每天都离不开。 然而这次好帮手 ChatGPT 却帮过头了&#xff0c;莫名奇妙的成为了“帮凶”&#xff0c;一位研究人员利用 ChatGPT 创建了虚假的数据集&#xff0c;用来支持未知的科学假设。…...

c#利用Forms.Timer定时检测Tcp连接状态

目的&#xff1a;本地创建客户端连接服务器端&#xff0c;如果连接正常显示连接正常如果连接异常显示连接异常。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.T…...

空间注意力:改变我们理解图像的方式

空间注意力&#xff1a;改变我们理解图像的方式 欢迎来到深度学习和计算机视觉的新时代&#xff0c;在这里&#xff0c;空间注意力机制正改变着我们理解和处理图像的方式。本文将深入探讨空间注意力的概念&#xff0c;它如何工作&#xff0c;以及为什么它在现代图像处理技术中…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

Java面试专项一-准备篇

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

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...

ubuntu22.04有线网络无法连接,图标也没了

今天突然无法有线网络无法连接任何设备&#xff0c;并且图标都没了 错误案例 往上一顿搜索&#xff0c;试了很多博客都不行&#xff0c;比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动&#xff0c;重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...