策略模式与简单工厂模式:终结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的混乱,那么这么做还有意义吗?

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/191119.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络扫盲(2)——网络边缘

一、概述 在计算机网络得到术语中&#xff0c;我们把与因特网相连的计算机或其他设备称为端系统&#xff08;或者主机&#xff09;&#xff0c;如下图所示&#xff0c;因为它们位于因特网的边缘&#xff0c;所以被称为端系统。因特网的端系统包括了桌面计算机&#xff…

Hdoop学习笔记(HDP)-Part.09 安装OpenLDAP

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

蓝桥杯day03——Bigram 分词

1.题目 给出第一个词 first 和第二个词 second&#xff0c;考虑在某些文本 text 中可能以 "first second third" 形式出现的情况&#xff0c;其中 second 紧随 first 出现&#xff0c;third 紧随 second 出现。 对于每种这样的情况&#xff0c;将第三个词 "th…

Android布局控件之LinearLayout、RelativeLayout、GridLayout、ScrollView

线性布局&#xff08;LinearLayout&#xff09; orientation horizontal:水平从左往右vertical:垂直从上到下若不指定orientation属性&#xff0c;默认为水平 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http:…

什么是DDoS攻击

DDoS攻击 1. 定义2. DDoS攻击类型2.1 网络层攻击2.2 传输层攻击2.3 应用层攻击 3.DDoS攻击态势特点 1. 定义 分布式拒绝服务&#xff08;DDoS&#xff09;攻击是一种常见的网络攻击形式。攻击者利用恶意程序对一个或多个目标发起攻击&#xff0c;企图通过大规模互联网流量耗尽…

微软与 OpenAI 宫斗大戏背后的故事【番外详细剖析篇】

​​微软和 OpenAI 曾精心制定了一个协议&#xff0c;目的是既要雄心勃勃又要确保安全地发布人工智能产品。然而&#xff0c;OpenAI 的董事会突然打破了所有这些精心策划的计划。 在感恩节前一个星期五的上午 11:30 左右&#xff0c;微软的首席执行官 Satya Nadella 正在和高层…

Git 简介及异常场景处理

一、简介 介绍Git之前&#xff0c;还得先介绍下 版本控制系统&#xff08;VCS&#xff09;&#xff0c; 和它的发展历史 纵观版本控制系统的发展历史&#xff0c;广义上讲&#xff0c;版本控制工具的历史可以分为三代&#xff1a; 第一代 第一代版本控制系统被称为本地版本控…

文艺复兴!ICO或再次兴起?香港Web3崛起前五部曲之一!

近日&#xff0c;香港证券及期货专业总会发布了《2024至2025年度财政预算案》&#xff0c;提出了一系列举措&#xff0c;其中最引人注目的莫过于政府考虑推出ICO发行机制&#xff0c;这一预算案被广泛视为香港在Web3崛起前的文艺复兴五部曲之一&#xff0c;引发了业界和投资者的…

关于 ls -s 输出文件大小的单位问题的讨论(stat 和ls -s的块不一样的,只是名称相同而已)

自己看书正好看到这里&#xff0c;正纳闷呢&#xff0c;上网查了下&#xff0c;发现不是我自己在为这个问题感到困惑。 有个大哥提出一个问题&#xff1a; 问题标题&#xff1a; ls -s的单位到底是什么&#xff1f; man ls -s, --size print the alloca…

MyBatis的创建,简单易懂的一篇blog

文章目录 一、MyBatis是什么二、操作流程三.配置resource总结 一、MyBatis是什么 MyBatis 是⼀款优秀的持久层框架&#xff0c;它⽀持⾃定义 SQL、存储过程以及⾼级映射。MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。MyBatis 可以通过简单的 XML 或注…

Azure Machine Learning - 使用 REST API 创建 Azure AI 搜索索引

本文介绍如何使用 Azure AI 搜索 REST AP和用于发送和接收请求的 REST 客户端以交互方式构建请求。 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0c;复旦机器人智能实验室成员&…

【计算机网络】14、DHCP

文章目录 一、概述1.1 好处 二、概念2.1 分配 IP2.2 控制租赁时间2.3 DHCP 的其他网络功能2.4 IP地址范围和用户类别2.5 安全 三、DHCP 消息3.1 DHCP discover message3.2 DHCP offers a message 如果没有 DHCP&#xff0c;IT管理者必须手动选出可用的 ip&#xff0c;这太耗时了…

TA-Lib学习研究笔记——Price Transform (五)

TA-Lib学习研究笔记——Price Transform &#xff08;五&#xff09; 1.AVGPRICE Average Price 函数名&#xff1a;AVGPRICE 名称&#xff1a;平均价格函数 语法&#xff1a; real AVGPRICE(open, high, low, close) df[AVGPRICE] tlb.AVGPRICE(df[open],df[high],df[low…

电子印章管理系统:是什么、3个平台推荐

说到印章&#xff0c;相信看过近现代电视剧的人都见过&#xff0c;一般在订立合约时最常用到&#xff0c;双方在合约上加盖印鉴&#xff0c;即代表着合约的成立。 我小时候还见过我父亲的印章&#xff0c;只是随着时代的发展&#xff0c;印章因为不易携带&#xff0c;容易被盗…

二叉树OJ题目——C语言

LeetCode 104.二叉树的最大深度 1. 题目描述&#xff1a; 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例…

CSS浅谈动画性能

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 目的一、举个栗子二、性能分析1.从图层分析2.性能分析 总结 目的 为了探究使用动画时&#xff0c;『transform』和『width、height、margin等』的差异 一、举个栗子…

【1】基于多设计模式下的同步异步日志系统

1. 项目介绍 本项⽬主要实现⼀个⽇志系统&#xff0c; 其主要⽀持以下功能: • ⽀持多级别⽇志消息 • ⽀持同步⽇志和异步⽇志 • ⽀持可靠写⼊⽇志到控制台、⽂件以及滚动⽂件中 • ⽀持多线程程序并发写⽇志 • ⽀持扩展不同的⽇志落地⽬标地 2. 开发环境 • CentOS 7 • vs…

Prism.js实现代码高亮并添加行号

先上效果: Prism.js Prism 是一款轻量、可扩展的代码语法高亮库&#xff0c;使用现代化的 Web 标准构建。 使用 Prismjs 可以快速为网站添加代码高亮功能&#xff0c;支持超过113中编程语言&#xff0c;还支持多种插件&#xff0c;是简洁、高效的代码高亮解决方案。 为什么选…

C++跨目录include问题

不同文件夹下使用预处理器指示符#include 使用举例 假设我们有如下一个工程&#xff0c;其中包含了几个源代码和头文件&#xff0c;其中main.cpp是主源代码文件&#xff0c;里面含有main函数&#xff1a; 在foldder main中包含&#xff1a;func4.hpp&#xff0c;func4.cpp&am…

1.0 十大经典排序算法

分类 算法 本系列算法整理自&#xff1a;https://github.com/hustcc/JS-Sorting-Algorithm 同时也参考了维基百科做了一些补充。 排序算法是《数据结构与算法》中最基本的算法之一。 排序算法可以分为内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#…