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

2023-12-02 19:15

本文主要是介绍策略模式与简单工厂模式:终结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混乱,让代码更清爽的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/446487

相关文章

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

SpringBoot中4种数据水平分片策略

《SpringBoot中4种数据水平分片策略》数据水平分片作为一种水平扩展策略,通过将数据分散到多个物理节点上,有效解决了存储容量和性能瓶颈问题,下面小编就来和大家分享4种数据分片策略吧... 目录一、前言二、哈希分片2.1 原理2.2 SpringBoot实现2.3 优缺点分析2.4 适用场景三、范围分片

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,