设计模式探索:策略模式

1. 什么是策略模式(Strategy Pattern)

定义

策略模式(Strategy Pattern)的原始定义是:定义一系列算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法可以独立于使用它的客户端而变化。

目的

策略模式的目的是在软件开发中,当实现某一个功能存在多种算法或者策略时,可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。
比如网购,你可以选择工商银行、农业银行、建设银行等等,但是它们提供的算法都是一致的,就是帮你付款。
在这里插入图片描述

角色

策略模式的主要角色如下:

  1. 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  2. 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  3. 环境或上下文(Context)类:是使用算法的角色,持有一个策略类的引用,最终给客户端调用。

UML类图

在策略模式中可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里每一个封装算法的类都可以被称为一种策略,为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做算法的声明.而每种算法对应一个具体的策略类。
在这里插入图片描述

实现代码

// 抽象策略类
public interface Strategy {void algorithm();
}// 具体策略类A
public class ConcreteStrategyA implements Strategy {@Overridepublic void algorithm() {System.out.println("执行策略A");}
}// 具体策略类B
public class ConcreteStrategyB implements Strategy {@Overridepublic void algorithm() {System.out.println("执行策略B");}
}// 环境类
public class Context {// 维持一个对抽象策略类的引用private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}// 调用策略类中的算法public void algorithm() {strategy.algorithm();}
}// 客户端代码
public class Client {public static void main(String[] args) {Strategy strategyA = new ConcreteStrategyA();Context context = new Context(strategyA); // 可以在运行时指定类型context.algorithm();}
}

2.优缺点

优点

  1. 易于扩展和维护:由于不同的算法被封装在不同的类中,所以我们可以很容易地添加新的算法或修改已有算法,而不需要修改客户端的代码。
  2. 提高代码的可读性:将不同的算法封装在不同的类中,使得代码更加模块化,易于理解和维护。
  3. 消除大量的条件语句:使用策略模式,我们可以将不同的算法替换成不同的类,从而消除大量的if-else语句,使得代码更加简洁和易于理解。

缺点

  1. 需要额外的类和接口:使用策略模式,我们需要为每个算法都创建一个独立的类,从而增加了代码的复杂度。
  2. 客户端需要知道所有的策略类:使用策略模式,客户端需要知道所有的策略类,以便在运行时选择合适的策略。这可能会增加代码的复杂度。

应用场景

策略模式适用于以下场景:

  1. 需要根据不同的条件选择不同的算法时:例如,计算器程序需要根据用户输入的运算符选择相应的计算方法。
  2. 需要在运行时动态地选择算法时:例如,某个系统需要根据用户的配置或环境变量来选择合适的算法。
  3. 需要将算法的实现细节与客户端代码分离时:例如,某个系统需要根据不同的数据来源来解析数据,但是客户端并不关心数据的解析细节。

总结

策略模式通过定义一系列算法,将每一个算法封装起来,并使它们可以相互替换,从而让算法可以独立于使用它的客户端而变化。通过使用策略模式,可以提高代码的扩展性、可读性和维护性,同时也可以消除大量的条件语句。

在工作中,为了消除代码中的大量 if-else 语句并提升代码的可维护性和扩展性,可以使用策略模式。下面是详细的实现步骤和代码示例。

3.如何用设计模式消除代码中的ifelse(你在工作中使用过哪些设计模式)

不使用设计模式

这是一个请假审批流程的代码示例,包含员工类、请假单类和审核类,直接使用 if-else 语句来处理不同的审批规则。

public class Employee {private String name; // 姓名private int level;   // 级别: P6, P7, P8// Constructor, getters and setters
}public class LeaveForm {private Employee employee; // 员工private String reason;     // 请假原因private int days;          // 天数private int type;          // 类型: 0-病假, 1-婚丧假, 2-年假// Constructor, getters and setters
}public class LeaveService {public void audit(LeaveForm leaveForm) {// 3天以下婚丧假, 自动通过if (leaveForm.getDays() <= 3 && leaveForm.getType() == 1) {System.out.println("三天以下婚丧假 无需审批自动通过!");}// 3天以上婚丧假else if (leaveForm.getDays() > 3 && leaveForm.getType() == 1) {System.out.println("三天以上婚丧假 进入上级审批流程!");}// 总经理请假else if (leaveForm.getEmployee().getLevel() == 9) {System.out.println("总经理请假无需审批自动通过!");}// 一天病假else if (leaveForm.getDays() == 1 && leaveForm.getType() == 0) {System.out.println("一天病假无需审批自动通过!");}// 一天以上病假else if (leaveForm.getDays() > 1 && leaveForm.getType() == 0) {System.out.println("一天以上病假进入审批流程!");}}
}

使用策略模式进行优化

通过策略模式,将所有的 if-else 分支的业务逻辑抽取为各种策略类,判断条件和执行逻辑封装到对应的策略类中,让客户端去依赖策略接口,保证具体策略类的改变不影响客户端。

策略接口
public interface AuditStrategy {boolean isSupport(LeaveForm leaveForm);void audit(LeaveForm leaveForm);int getPriority();String getName();
}
具体策略类
public class AuditStrategyImpl_1 implements AuditStrategy {@Overridepublic boolean isSupport(LeaveForm leaveForm) {return leaveForm.getDays() <= 3 && leaveForm.getType() == 1;}@Overridepublic void audit(LeaveForm leaveForm) {System.out.println(leaveForm);System.out.println("三天以下婚丧假 无需审批自动通过!");}@Overridepublic int getPriority() {return 0;}@Overridepublic String getName() {return "三天以下婚假审批规则";}
}public class AuditStrategyImpl_2 implements AuditStrategy {@Overridepublic boolean isSupport(LeaveForm leaveForm) {return leaveForm.getDays() > 3 && leaveForm.getType() == 1;}@Overridepublic void audit(LeaveForm leaveForm) {System.out.println(leaveForm);System.out.println("三天以上婚丧假 进入上级审批流程!");}@Overridepublic int getPriority() {return 0;}@Overridepublic String getName() {return "三天以上婚丧假审批规则";}
}public class AuditStrategyImpl_3 implements AuditStrategy {@Overridepublic boolean isSupport(LeaveForm leaveForm) {return leaveForm.getEmployee().getLevel() == 9;}@Overridepublic void audit(LeaveForm leaveForm) {System.out.println(leaveForm);System.out.println("总经理请假无需审批自动通过!");}@Overridepublic int getPriority() {return 999;}@Overridepublic String getName() {return "总经理请假审批规则";}
}
策略工厂
public class AuditStrategyFactory {private final static AuditStrategyFactory factory = new AuditStrategyFactory();private List<AuditStrategy> auditStrategyList = new ArrayList<>();private AuditStrategyFactory() {auditStrategyList.add(new AuditStrategyImpl_1());auditStrategyList.add(new AuditStrategyImpl_2());auditStrategyList.add(new AuditStrategyImpl_3());// Add more strategies here}public static AuditStrategyFactory getInstance() {return factory;}public AuditStrategy getAuditStrategy(LeaveForm leaveForm) {AuditStrategy auditStrategy = null;for (AuditStrategy strategy : auditStrategyList) {if (strategy.isSupport(leaveForm)) {if (auditStrategy == null || strategy.getPriority() > auditStrategy.getPriority()) {auditStrategy = strategy;}}}if (auditStrategy == null) {throw new RuntimeException("没有匹配到请假审核规则");}return auditStrategy;}
}
业务类
public class LeaveServiceNew {public void audit(LeaveForm leaveForm) {AuditStrategyFactory factory = AuditStrategyFactory.getInstance();AuditStrategy strategy = factory.getAuditStrategy(leaveForm);strategy.audit(leaveForm);}
}
测试
public class Client {public static void main(String[] args) {LeaveServiceNew leaveServiceNew = new LeaveServiceNew();LeaveForm form1 = new LeaveForm(new Employee("李总经理", 9), "甲流发烧", 10, 0);leaveServiceNew.audit(form1);LeaveForm form2 = new LeaveForm(new Employee("打工人1", 2), "甲流发烧", 2, 0);leaveServiceNew.audit(form2);LeaveForm form3 = new LeaveForm(new Employee("打工人2", 3), "结婚", 2, 1);leaveServiceNew.audit(form3);LeaveForm form4 = new LeaveForm(new Employee("打工人3", 4), "请年假,休息休息", 5, 2);leaveServiceNew.audit(form4);}
}
添加新规则

如果需要添加新的年假规则,只需要创建新的策略类并添加到工厂中即可。

public class AuditStrategyImpl_6 implements AuditStrategy {@Overridepublic boolean isSupport(LeaveForm leaveForm) {return leaveForm.getType() == 2;}@Overridepublic void audit(LeaveForm leaveForm) {System.out.println(leaveForm);System.out.println("查询您的剩余年假天数...");System.out.println("剩余年假还有6天, 进入审批流程");}@Overridepublic int getPriority() {return 0;}@Overridepublic String getName() {return "年假审批规则";}
}

在工厂类中添加新的策略:

private AuditStrategyFactory() {auditStrategyList.add(new AuditStrategyImpl_1());auditStrategyList.add(new AuditStrategyImpl_2());auditStrategyList.add(new AuditStrategyImpl_3());auditStrategyList.add(new AuditStrategyImpl_6()); // 新添加的年假规则// Add more strategies here
}

通过这种方式,已经成功消除了 if-else 结构,每当新来了一种请假规则,只需要添加新的规则处理策略,并修改工厂中的集合。如果要使得程序符合开闭原则,可以通过反射机制,动态地加载策略类。

使用反射机制动态加载策略类
public class AuditStrategyFactory {private final static AuditStrategyFactory factory = new AuditStrategyFactory();private List<AuditStrategy> auditStrategyList = new ArrayList<>();private AuditStrategyFactory() {// 动态加载策略类try {String packageName = "com.example.strategies"; // 策略类所在包名ClassLoader classLoader = Thread.currentThread().getContextClassLoader();String path = packageName.replace('.', '/');Enumeration<URL> resources = classLoader.getResources(path);List<File> dirs = new ArrayList<>();while (resources.hasMoreElements()) {URL resource = resources.nextElement();dirs.add(new File(resource.getFile()));}for (File directory : dirs) {auditStrategyList.addAll(findClasses(directory, packageName));}} catch (Exception e) {e.printStackTrace();}}private List<AuditStrategy> findClasses(File directory, String packageName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {List<AuditStrategy> strategies = new ArrayList<>();if (!directory.exists()) {return strategies;}File[] files = directory.listFiles();for (File file : files) {if (file.isDirectory()) {strategies.addAll(findClasses(file, packageName + "." + file.getName()));} else if (file.getName().endsWith(".class")) {String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);Class<?> clazz = Class.forName(className);if (AuditStrategy.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {strategies.add((AuditStrategy) clazz.newInstance());}}}return strategies;}public static AuditStrategyFactory getInstance() {return factory;}public AuditStrategy getAuditStrategy(LeaveForm leaveForm) {AuditStrategy auditStrategy = null;for (AuditStrategy strategy : auditStrategyList) {if (strategy.isSupport(leaveForm)) {if (auditStrategy == null || strategy.getPriority() > auditStrategy.getPriority()) {auditStrategy = strategy;}}}if (auditStrategy == null) {throw new RuntimeException("没有匹配到请假审核规则");}return auditStrategy;}
}

通过这种方式,策略类可以动态地从指定包中加载,实现了真正的开闭原则。

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

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

相关文章

算法day03 桶排序 数据结构分类 时间复杂度 异或运算

学数据结构之前 必看_哔哩哔哩_bilibili 1.认识复杂度和简单排序算法_哔哩哔哩_bilibili 桶排序&#xff08;Bucket sort&#xff09;------时间复杂度为O(n)的排序方法&#xff08;一&#xff09;_多桶排序时间复杂度-CSDN博客 桶排序 测试场景&#xff1a;数组中有10000个随…

PyTorch SummaryWriter TensorBoard 中进行可视化

在 PyTorch 中&#xff0c;SummaryWriter 通常用于在训练过程中记录各种数据&#xff0c;以便在 TensorBoard 中进行可视化。 - 安装&#xff1a; pip install tensorboard -i https://mirrors.aliyun.com/pypi/simple/ from torch.utils.tensorboard import SummaryWriter…

MVC分页

public ActionResult Index(int ? page){IPagedList<EF.ACCOUNT> userPagedList;using (EF.eMISENT content new EF.eMISENT()){第几页int pageNumber page ?? 1;每页数据条数&#xff0c;这个可以放在配置文件中int pageSize 10;//var infoslist.C660List.OrderBy(…

2.电容(常见元器件及电路基础知识)

一.电容种类 1.固态电容 这种一般价格贵一些&#xff0c;ESR,ESL比较低,之前项目400W电源用的就是这个&#xff0c;温升能够很好的控制 2.铝电解电容 这种一般很便宜&#xff0c;ESR,ESL相对大一些&#xff0c;一般发热量比较大&#xff0c;烫手。 这种一般比上一个贵一点&am…

【人工智能】-- 反向传播

个人主页&#xff1a;欢迎来到 Papicatch的博客 课设专栏 &#xff1a;学生成绩管理系统 专业知识专栏&#xff1a; 专业知识 文章目录 &#x1f349;引言 &#x1f349;反向传播 &#x1f348;定义 &#x1f348;反向传播的作用 &#x1f34d;参数优化 &#x1f34d;学…

docker也能提权??内网学习第6天 rsync未授权访问覆盖 sudo(cve-2021-3156)漏洞提权 polkit漏洞利用

现在我们来说说liunx提权的操作&#xff1a;前面我们说了环境变量&#xff0c;定时任务来进行提权的操作 rsync未授权访问覆盖 我们先来说说什么是rsync rsync是数据备份工具&#xff0c;默认是开启的873端口 我们在进行远程连接的时候&#xff0c;如果它没有让我们输入账号…

Python高级(三)_正则表达式

Python高级-正则表达式 第三章 正则表达式 在开发中会有大量的字符串处理工作,其中经常会涉及到字符串格式的校验。 1、正则表达式概述 正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、…

论文学习_Getafix: learning to fix bugs automatically

1. 引言 研究背景:现代生产代码库极其复杂并且不断更新。静态分析器可以帮助开发人员发现代码中的潜在问题(在本文的其余部分中称为错误),这对于在这些大型代码库中保持高代码质量是必要的。虽然通过静态分析尽早发现错误是有帮助的,但修复这些错误的问题在实践中仍然主要…

51单片机STC89C52RC——16.1 五线四相步进电机

目录 目的/效果 一&#xff0c;STC单片机模块 二&#xff0c;步进电机 2.2 什么是步进电机&#xff1f; 2.2.1 步进电机驱动板 静态参数 动态参数 2.2.2 五线四相 单相激励步进 双相激励步进 混合激励驱动 2.3 细分驱动 2.4 通过数字信号控制旋转位置和转速。 2…

第一次参加数学建模竞赛新手小白备赛经验贴

2024年暑假已经来临&#xff0c;下半年的数学建模竞赛非常多&#xff0c;许多同学可能是第一次参赛&#xff0c;对于如何准备感到迷茫和无从下手。在这种情况下&#xff0c;我们将分享一些备赛的小技巧&#xff0c;帮助大家在这个暑假更好的入门&#xff0c;即便是零基础的小白…

resistronic焊接机RMF10 RE120安装SSK10说明操作

resistronic焊接机RMF10 RE120安装SSK10说明操作

新零售起盘案例「半藏酱酒」布局路径,半藏总院分院招商模式

在当前白酒市场中&#xff0c;一款名为半藏酒的酒品以其独特的新零售模式引起了广泛关注。这种模式不同于传统销售方式&#xff0c;通过多种创新玩法&#xff0c;实现了销售与品牌推广的双重目标&#xff0c;让我们一起来看看细节。 半藏酒的分级代理制度将代理商分为两个层级&…

如何录制屏幕视频?4款软件,轻松录屏

在数字化飞速发展的时代&#xff0c;如何录制屏幕视频已经成为我们工作、学习和娱乐中不可省略的一个重要问题。无论是制作教学教程还是录制游戏视频等&#xff0c;屏幕视频录制都为我们提供了极大的便利。今天&#xff0c;就让我们一起探索如何录制屏幕视频的精彩方式&#xf…

Go 1.19.4 函数-Day 08

1. 函数概念和调用原理 1.1 基本介绍 函数是基本的代码块&#xff0c;用于执行一个任务。 Go 语言最少有个 main() 函数。 你可以通过函数来划分不同功能&#xff0c;逻辑上每个函数执行的是指定的任务。 函数声明告诉了编译器函数的名称&#xff0c;返回类型&#xff0c;和参…

单片机中有FLASH为啥还需要EEROM?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 一是EEPROM操作简单&…

Java版Flink使用指南——将消息写入到RabbitMQ的队列中

大纲 新建工程新增依赖 编码自动产生数据写入RabbitMQ 测试工程代码 在 《Java版Flink使用指南——从RabbitMQ中队列中接入消息流》一文中&#xff0c;我们介绍了如何使用Java在Flink中读取RabbitMQ中的数据&#xff0c;并将其写入日志中。本文将通过代码产生一些数据&#xf…

未解之谜----macOS版fiddler everywhere 如何将当前会话保存成一个txt文件查看

如图&#xff0c;这是win版的保存方式&#xff0c;mac上面根本没有这个按钮&#xff0c;找的很崩溃

nx软件许可优化解决方案

Nx软件介绍 来自SiemensPLM 的 NX使企业能够通过新一代数字化产品开发系统实现向产品全生命周期管理转型的目标。 NX 包含了企业中应用最广泛的集成应用套件&#xff0c;用于产品设计、工程和制造全范围的开发过程。 如今制造业所面临的挑战是&#xff0c;通过产品开发的技术创…

【数据结构】排序——快速排序

前言 本篇博客我们继续介绍一种排序——快速排序&#xff0c;让我们看看快速排序是怎么实现的 &#x1f493; 个人主页&#xff1a;小张同学zkf ⏩ 文章专栏&#xff1a;数据结构 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 ​ 目录 …

LinK3D: Linear Keypoints Representation for 3D LiDAR Point Cloud【翻译与解读】

LinK3D: Linear Keypoints Representation for 3D LiDAR Point Cloud 摘要 特征提取和匹配是许多机器人视觉任务的基本组成部分&#xff0c;如 2D 或 3D 目标检测、识别和配准。2D 特征提取和匹配已取得巨大成功。然而&#xff0c;在 3D 领域&#xff0c;当前方法由于描述性差…