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

策略模式的实现与应用:掌握灵活算法切换的技巧

文章目录

  • 常用的设计模式有以下几种:
    • 一.创建型模式(Creational Patterns):
    • 二.结构型模式(Structural Patterns):
    • 三.行为型模式(Behavioral Patterns):
    • 四.并发模式(Concurrent Patterns):
  • 策略模式概念
  • 一、策略模式例子一
  • 二、策略模式例子二
  • 三、策略模式例子三
  • 总结


常用的设计模式有以下几种:

一.创建型模式(Creational Patterns):

工厂模式(Factory Pattern)
抽象工厂模式(Abstract Factory Pattern)
单例模式(Singleton Pattern)
原型模式(Prototype Pattern)
建造者模式(Builder Pattern)

二.结构型模式(Structural Patterns):

适配器模式(Adapter Pattern)
桥接模式(Bridge Pattern)
装饰器模式(Decorator Pattern)
组合模式(Composite Pattern)
外观模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)

三.行为型模式(Behavioral Patterns):

策略模式(Strategy Pattern)
观察者模式(Observer Pattern)
迭代器模式(Iterator Pattern)
命令模式(Command Pattern)
模板方法模式(Template Method Pattern)
职责链模式(Chain of Responsibility Pattern)
状态模式(State Pattern)
访问者模式(Visitor Pattern)
中介者模式(Mediator Pattern)
备忘录模式(Memento Pattern)
解释器模式(Interpreter Pattern)

四.并发模式(Concurrent Patterns):

单例模式(Singleton Pattern,在多线程环境下的应用)
生成器模式(Builder Pattern,在多线程环境下的应用)
保护性暂停模式(Guarded Suspension Pattern)
观察者模式(Observer Pattern,在多线程环境下的应用)

这些设计模式涵盖了对象的创建、对象间的组织和交互、以及对象的行为等方面,可以帮助开发者更好地组织和设计代码,提高代码的可扩展性、可维护性以及重用性。需要根据实际情况选择适合的设计模式来解决问题。


策略模式概念

今天来讲一讲策略模式:
策略模式(Strategy Pattern)是一种行为设计模式,它允许你定义一系列算法,并将每个算法封装到独立的类中,使它们可以互相替换。策略模式使得算法的变化独立于使用它们的客户端。
在策略模式中,有一个上下文(Context)对象,它持有一个策略接口的引用,并通过调用策略接口的方法来执行具体的算法。算法类实现了策略接口,每个算法类都封装了一种具体的算法,客户端可以根据需要选择不同的策略对象,从而实现不同的行为。🤩🤩🤩
策略模式的优点包括:

1. 算法可以灵活地替换或新增,不影响使用算法的客户端。
2. 可以消除大量的条件语句,提高代码的可维护性和可读性。
3. 可以将算法的实现细节封装起来,提高代码的模块性和复用性。

策略模式在许多场景下都有应用,比如排序算法、计算费用、验证用户等。通过使用策略模式,可以优雅地处理复杂的逻辑,并提供一种可扩展、易于维护的解决方案。🤗🤗🤗

我并不喜欢看含义,对于这种概念性的东西,动手实践才是硬道理!
以下举出 策略模式 的几个 荔枝!!!😍😍😍
相信看完会更加理解策略模式的强大性!

在这里插入图片描述

一、策略模式例子一

假设我们正在开发一个商场收银系统,其中有不同的折扣策略供用户选择,包括无折扣、固定折扣和打折折扣。我们希望通过策略模式来实现这些不同的折扣策略。
首先,我们定义一个抽象的策略接口 DiscountStrategy,它声明了一个计算折扣金额的方法 calculateDiscount:

public interface DiscountStrategy {double calculateDiscount(double amount);
}

然后,我们分别实现三种具体的策略类:NoDiscountStrategy(无折扣)、FixedDiscountStrategy(固定折扣)和PercentageDiscountStrategy(打折折扣)。它们都实现了 DiscountStrategy 接口:

public class NoDiscountStrategy implements DiscountStrategy {@Overridepublic double calculateDiscount(double amount) {return 0; // 无折扣,返回0}
}public class FixedDiscountStrategy implements DiscountStrategy {private double discount;public FixedDiscountStrategy(double discount) {this.discount = discount;}@Overridepublic double calculateDiscount(double amount) {return discount; // 固定折扣,直接返回固定的折扣金额}
}public class PercentageDiscountStrategy implements DiscountStrategy {private double percentage;public PercentageDiscountStrategy(double percentage) {this.percentage = percentage;}@Overridepublic double calculateDiscount(double amount) {return amount * percentage; // 打折折扣,根据折扣比例计算折扣金额}
}

最后,我们定义一个上下文类 Cashier,它持有一个 DiscountStrategy 的引用,并在结算时调用该策略的方法:

public class Cashier {private DiscountStrategy discountStrategy;public void setDiscountStrategy(DiscountStrategy discountStrategy) {this.discountStrategy = discountStrategy;}public double calculateTotalWithDiscount(double amount) {double discount = discountStrategy.calculateDiscount(amount);return amount - discount;}
}

现在,我们可以使用策略模式来实现商场收银系统的折扣功能了。示例如下:

public class Main {public static void main(String[] args) {Cashier cashier = new Cashier();// 设置无折扣策略DiscountStrategy noDiscountStrategy = new NoDiscountStrategy();cashier.setDiscountStrategy(noDiscountStrategy);double total = cashier.calculateTotalWithDiscount(100);System.out.println("Total with no discount: " + total);// 设置固定折扣策略DiscountStrategy fixedDiscountStrategy = new FixedDiscountStrategy(20);cashier.setDiscountStrategy(fixedDiscountStrategy);total = cashier.calculateTotalWithDiscount(100);System.out.println("Total with fixed discount: " + total);// 设置打折折扣策略DiscountStrategy percentageDiscountStrategy = new PercentageDiscountStrategy(0.1);cashier.setDiscountStrategy(percentageDiscountStrategy);total = cashier.calculateTotalWithDiscount(100);System.out.println("Total with percentage discount: " + total);}
}

输出结果:

Total with no discount: 100.0
Total with fixed discount: 80.0
Total with percentage discount: 90.0

通过策略模式,我们可以灵活地选择不同的折扣策略,并在运行时动态地切换和应用这些策略,而不需要修改 Cashier 类的代码。这样,我们可以方便地添加新的折扣策略或修改现有策略的实现,而不会对其他部分产生影响。这样的设计符合开闭原则,增加了代码的可维护性和扩展性。

二、策略模式例子二

例子2:排序算法
假设我们正在设计一个排序工具,它可以根据用户选择的不同排序算法对数据进行排序。我们可以使用策略模式来实现不同的排序策略。
首先,我们定义一个排序策略接口 SortingStrategy,它声明了一个排序方法 sort:

public interface SortingStrategy {void sort(int[] array);
}

然后,我们分别实现两种具体的策略类:BubbleSortStrategy(冒泡排序)和 QuickSortStrategy(快速排序)。它们都实现了 SortingStrategy 接口:

public class BubbleSortStrategy implements SortingStrategy {@Overridepublic void sort(int[] array) {// 冒泡排序算法的具体实现// ...}
}public class QuickSortStrategy implements SortingStrategy {@Overridepublic void sort(int[] array) {// 快速排序算法的具体实现// ...}
}

最后,我们定义一个上下文类 Sorter,它持有一个 SortingStrategy 的引用,并在排序时调用该策略的方法:

public class Sorter {private SortingStrategy sortingStrategy;public void setSortingStrategy(SortingStrategy sortingStrategy) {this.sortingStrategy = sortingStrategy;}public void sortArray(int[] array) {sortingStrategy.sort(array);}
}

现在,我们可以使用策略模式来实现排序工具了。示例如下:

public class Main {public static void main(String[] args) {Sorter sorter = new Sorter();// 使用冒泡排序策略SortingStrategy bubbleSortStrategy = new BubbleSortStrategy();sorter.setSortingStrategy(bubbleSortStrategy);int[] array = {5, 3, 8, 2, 1};sorter.sortArray(array);System.out.println("Sorted array using bubble sort:");for (int num : array) {System.out.print(num + " ");}System.out.println();// 使用快速排序策略SortingStrategy quickSortStrategy = new QuickSortStrategy();sorter.setSortingStrategy(quickSortStrategy);int[] array2 = {9, 4, 6, 2, 7};sorter.sortArray(array2);System.out.println("Sorted array using quick sort:");for (int num : array2) {System.out.print(num + " ");}System.out.println();}
}

输出结果:

Sorted array using bubble sort:
1 2 3 5 8 
Sorted array using quick sort:
2 4 6 7 9

通过策略模式,我们可以灵活地选择不同的排序策略,而不需要修改 Sorter 类的代码。这样,我们可以方便地添加新的排序策略或修改现有策略的实现,而不会对其他部分产生影响。

三、策略模式例子三

假设我们正在开发一个电商平台,针对不同的用户类型(普通用户、VIP用户、管理员),我们需要为其提供不同的登录方式。
首先,我们定义一个登录策略接口 LoginStrategy,它声明了一个登录方法 login:

public interface LoginStrategy {void login();
}

然后,我们分别实现三种具体的策略类:DefaultLoginStrategy(普通用户登录方式)、VIPLoginStrategy(VIP用户登录方式)和 AdminLoginStrategy(管理员登录方式)。它们都实现了 LoginStrategy 接口:

public class DefaultLoginStrategy implements LoginStrategy {@Overridepublic void login() {System.out.println("使用用户名和密码登录");// 具体的登录逻辑}
}public class VIPLoginStrategy implements LoginStrategy {@Overridepublic void login() {System.out.println("使用手机号和密码登录");// 具体的登录逻辑}
}public class AdminLoginStrategy implements LoginStrategy {@Overridepublic void login() {System.out.println("使用管理员账号和密码登录");// 具体的登录逻辑}
}

最后,我们定义一个上下文类 LoginContext,它持有一个 LoginStrategy 的引用,并在登录时调用该策略的方法:

public class LoginContext {private LoginStrategy loginStrategy;public void setLoginStrategy(LoginStrategy loginStrategy) {this.loginStrategy = loginStrategy;}public void performLogin() {loginStrategy.login();}
}

现在,我们可以使用策略模式来为不同的用户类型提供不同的登录方式了。示例如下:

public class Main {public static void main(String[] args) {LoginContext loginContext = new LoginContext();// 普通用户登录LoginStrategy defaultLoginStrategy = new DefaultLoginStrategy();loginContext.setLoginStrategy(defaultLoginStrategy);loginContext.performLogin();// VIP用户登录LoginStrategy vipLoginStrategy = new VIPLoginStrategy();loginContext.setLoginStrategy(vipLoginStrategy);loginContext.performLogin();

总结

UU们,懂了嘛!!!😄😄😄
以下是实际开发中常用的几个例子,展示了策略模式的应用:

支付方式:
在电商平台上,用户可以选择不同的支付方式进行支付,比如支付宝、微信支付、银行卡支付等。这些支付方式都具备支付的功能,但其实现方式和支付逻辑可能有所不同。策略模式可以用于将不同的支付方式封装成不同的策略类,然后在运行时根据用户选择的支付方式来选择相应的策略进行支付。

缓存策略:
在系统开发中,我们经常会使用缓存来提高系统性能。不同的数据操作可能需要不同的缓存策略,比如基于时间的过期策略、基于LRU(Least
Recently Used)的淘汰策略、基于LFU(Least Frequently
Used)的淘汰策略等。策略模式可以用于封装不同的缓存策略为不同的策略类,然后在运行时选择相应的缓存策略进行数据操作。

图像处理:
在图像处理应用中,我们可能需要应用不同的滤镜或特效来处理图像,比如黑白滤镜、模糊滤镜、锐化滤镜等。这些滤镜都具备处理图像的功能,但实现方式和处理逻辑可能有所不同。策略模式可以用于将不同的滤镜或特效封装成不同的策略类,然后在运行时根据用户选择的滤镜或特效来选择相应的策略进行图像处理。

日志记录级别:
在日志记录应用中,不同的日志级别对应不同的日志输出方式,比如普通日志输出到控制台,警告日志输出到文件,错误日志发送邮件等等。策略模式可以用于封装不同的日志记录级别为不同的策略类,然后在运行时根据日志级别选择相应的策略进行日志记录。

这些都是在实际开发中常用的例子,策略模式可以帮助我们根据不同的条件和需求来选择相应的策略进行处理,提供了灵活性和扩展性。它可以将不同的策略封装起来,使客户端代码与具体策略的实现解耦,从而提高代码的可维护性和可测试性。
(注意:是不同的处理逻辑,如果你只是根据不同类型查数据库一张表的数据,那就没啥必要了)
不懂或者有什么错误的地方,欢迎评论区留言,俺可以再举更多的 荔枝~~~

@作者:加辣椒了吗?
简介:憨批大学生一枚,喜欢在博客上记录自己的学习心得,也希望能够帮助到你们!
在这里插入图片描述

相关文章:

策略模式的实现与应用:掌握灵活算法切换的技巧

文章目录 常用的设计模式有以下几种:一.创建型模式(Creational Patterns):二.结构型模式(Structural Patterns):三.行为型模式(Behavioral Patterns):四.并发…...

当ChatGPT应用在汽车行业,具体有哪些场景?

​ ChatGPT有潜力彻底改变汽车行业并将其提升到新的高度。在ChatGPT的加持下,该行业的多个领域都将取得重大变化。 利用ChatGPT作更高级的虚拟助理 你可能用过现有的虚拟助理,它们一系列的回复有时候让人不得不感叹一句“人工智障”!然而&a…...

行为型-中介者模式(Mediator Pattern)

概述 中介者模式(Mediator Pattern)是一种行为型设计模式,它通过封装一系列对象之间的交互方式,使这些对象能够互相通信而不需要直接相互引用。中介者模式通过集中控制对象的交互,使得对象之间的耦合度降低&#xff0…...

Kibana+Prometheus+node_exporter 监控告警部署

下载好三个软件包 一、prometheus安装部署 1、解压 linxxubuntu:~/module$ tar -xvf prometheus-2.45.0-rc.0.linux-amd64.tar.gz 2、修改配置文件的IP地址 # my global config global:scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is ever…...

【前端知识】JavaScript——设计模式(工厂模式、构造函数模式、原型模式)

【前端知识】JavaScript——设计模式(工厂模式、构造函数模式、原型模式) 一、工厂模式 工厂模式是一种众所周知的设计模式,广泛应用于软件工程领域,用于抽象创建特定对象的过程。 优点:可以解决创建多个类似对象的…...

未来的算法备案法规:创新和安全如何兼顾?

随着科技的快速发展,算法正逐步渗透到我们生活的各个方面,从推荐引擎到自动驾驶,从医疗诊断到金融交易,这一现象既充满希望,也充满了挑战。其中一个关键的挑战就是如何设计和实施有效的算法备案法规,以促进…...

pycharm 使用远程服务器 jupyter (本地jupyter同理)

1. 远程服务器miniconda 环境中创建jupyter环境 # 1. 激活环境 conda activate envname#2. 在环境中安装jupyter pip install jupyter # 或者 conda install jupyter#3. 生成jupyter_notebook_config.py文件 jupyter notebook --generate-config#4. 设置密码 jupyter noteboo…...

leetcode 376. 摆动序列

2023.7.28 本题思路是定义一个 direct变量记录上一次摆动是上坡还是下坡 。 然后在一个for循环中循环判断当前摆动和上一次摆动是否一致,如果不一致则视为一次摆动。 如果前后元素值相等得话,直接continue进入下一次循环。 下面看代码: clas…...

【图像处理】使用自动编码器进行图像降噪(改进版)

阿里雷扎凯沙瓦尔兹 一、说明 自动编码器是一种学习压缩和重建输入数据的神经网络。它由一个将数据压缩为低维表示的编码器和一个从压缩表示中重建原始数据的解码器组成。该模型使用无监督学习进行训练,旨在最小化输入和重建输出之间的差异。自动编码器可用于降维、…...

MySQL大数据量分页查询方法及其优化

---方法1: 直接使用数据库提供的SQL语句 ---语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N ---适应场景: 适用于数据量较少的情况(元组百/千级) ---原因/缺点: 全表扫描,速度会很慢 且 有的数据库结果集返回不稳定(如某次返回1,2,3,另外的一次返回2,1,3). L…...

dataTable转成对象、json、list

datatable转换成list集合 public static T TableToEntity<T>(DataTable dt, int rowindex 0, bool isStoreDB true){Type type typeof(T);T entity Activator.CreateInstance<T>();if (dt null){return entity;}DataRow row dt.Rows[rowindex];PropertyInfo…...

ubuntu环境安装centos7虚拟机网络主机不可达,ping不通

【NAT模式下解决】1.首先vi /etc/sysconfig/network-scripts/ifcfg-ens33检查ONBOOTyes&#xff0c;保存 2.输入systemctl restart network命令重启网关...

STN:Spatial Transformer Networks

1.Abstract 卷积神经网络缺乏对输入数据保持空间不变的能力&#xff0c;导致模型性能下降。作者提出了一种新的可学习模块&#xff0c;STN。这个可微模块可以插入现有的卷积结构中&#xff0c;使神经网络能够根据特征图像本身&#xff0c;主动地对特征图像进行空间变换&#x…...

C语言学习笔记 VScode设置C环境-06

目录 一、下载vscode软件 二、安装minGW软件 三、VS Code安装C/C插件 3.1 搜索并安装C/C插件 3.2 配置C/C环境 总结 一、下载vscode软件 在官网上下载最新的版本 Download Visual Studio Code - Mac, Linux, Windowshttps://code.visualstudio.com/download 二、安装minGW…...

alias取别名后,另一个shell中和shell脚本中不生效的问题以及crontab执行docker失败问题

目录 问题一&#xff1a;用alias取别名后&#xff0c;另一个shell中不生效描述原因解决 问题二&#xff1a;用alias取别名后&#xff0c;别名在脚本中不生效描述原因解决 问题三&#xff1a;crontab计划任务不能运行docker命令描述原因解决 问题一&#xff1a;用alias取别名后&…...

Shell ❀ 一键配置Iptables规则脚本 (HW推荐)

文章目录 注意事项1. 地址列表填写规范2. 代码块3. 执行结果4. 地址与端口获取方法4.1 tcpdump抓包分析&#xff08;推荐使用&#xff09;4.2 TCP连接分析&#xff08;仅能识别TCP连接&#xff09; 注意事项 请务必按照格式填写具体参数&#xff0c;否则会影响到匹配规则的创建…...

linux服务器查找大文件及删除文件后磁盘空间没有得到释放

1、查询服务器中大于1G的文件 find / -type f -size 1G这条命令是查询自”/”根目录下所有大小超过1G的文件&#xff0c;查询的大小可以根据需要改变&#xff0c;如下&#xff1a; 相关查询&#xff1a;查询服务器中大于100M的文件 find / -type f -size 100M2、查询服务器中…...

Java那些“锁”事 - 死锁及排查

死锁是两个或者两个以上的线程在执行过程中&#xff0c;因争夺资源而造成的一种互斥等待现象&#xff0c;若没有外界干涉那么它们将无法推进下去。如果系统资源不足&#xff0c;进程的资源请求都得到满足&#xff0c;死锁出现的可能性就很低&#xff0c;否则就会因为争夺有限的…...

LLM系列 | 18 : 如何用LangChain进行网页问答

简介 一夕轻雷落万丝&#xff0c;霁光浮瓦碧参差。 紧接之前LangChain专题文章&#xff1a; 15:如何用LangChain做长文档问答&#xff1f;16:如何基于LangChain打造联网版ChatGPT&#xff1f;17:ChatGPT应用框架LangChain速成大法 今天这篇小作文是LangChain实践专题的第4…...

Aspose.cell excel转pdf日期格式不正确yyyy/MM/dd变成MM/dd/yyyy

最近使用Aspose.cell将excel转pdf过程中excel中时间格式列的显示和excel表里的值显示不一样。 excel里日期格式 yyyy/MM/dd pdf里日期格式MM/dd/yyyy 主要原因&#xff1a;linux和windows里内置的时间格式不一致&#xff0c;当代码部署到linux服务器的时候转换格式就会发生不一…...

搭建golang开发环境

这里参考一篇文章&#xff1a; golang环境变量链接&#xff0c;还不错...

Django实现音乐网站 ⑴

使用Python Django框架制作一个音乐网站。 目录 网站功能模块 安装django 创建项目 创建应用 注册应用 配置数据库 设置数据库配置 设置pymysql库引用 创建数据库 创建数据表 生成表迁移文件 执行表迁移 后台管理 创建管理员账户 启动服务器 登录网站 配置时区…...

基于粒子群优化算法的分布式电源选址与定容【多目标优化】【IEEE33节点】(Matlab代码实现)

目录 &#x1f4a5;1 概述 1.1 目标函数 2.2 约束条件 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码实现 &#x1f4a5;1 概述 分布式电源接入配电网&#xff0c;实现就地消纳&#xff0c;可以提高新能源的利用率、提高电能质量和降低系统网损…...

打卡一个力扣题目

目录 一、问题 二、解题办法一 三、解题方法二 四、对比分析 关于 ARTS 的释义 —— 每周完成一个 ARTS&#xff1a; ● Algorithm: 每周至少做一个 LeetCode 的算法题 ● Review: 阅读并点评至少一篇英文技术文章 ● Tips: 学习至少一个技术技巧 ● Share: 分享一篇有观点…...

【SSM—SpringMVC】 问题集锦(持续更新)

目录 1.Tomcat启动&#xff0c;部署工件失败 1.Tomcat启动&#xff0c;部署工件失败 解决&#xff1a;使用SpringMVC&#xff0c;添加Web支持&#xff0c;要将项目结构进行添加WEB-INF下添加lib目录&#xff0c;将依赖添进去...

2022年全国职业院校技能大赛(高职组)“软件测试”赛项接口测试任务书

任务七 接口测试 执行接口测试 本部分按照要求&#xff0c;执行接口测试&#xff1b;使用接口测试工具PostMan&#xff0c;编写脚本、配置参数、执行接口测试并且截图&#xff0c;截图需粘贴在接口测试总结报告中。 接口测试具体要求如下&#xff1a; 题目1&#xff1a;资产…...

Docker 如何助您成为数据科学家

一、说明 在过去的 5 年里&#xff0c;我听到了很多关于 docker 容器的嗡嗡声。似乎我所有的软件工程朋友都在使用它们来开发应用程序。我想弄清楚这项技术如何使我更有效率&#xff0c;但我发现网上的教程要么太详细&#xff1a;阐明我作为数据科学家永远不会使用的功能&#…...

机器学习01 -Hello World(对鸢尾花(Iris Flower)进行训练及测试)

什么是机器学习&#xff1f; 机器学习是一种人工智能&#xff08;AI&#xff09;的子领域&#xff0c;它探索和开发计算机系统&#xff0c;使其能够从数据中学习和改进&#xff0c;并在没有明确编程指令的情况下做出决策或完成任务。 传统的程序需要程序员明确编写指令来告诉…...

android studio JNI开发

一、JNI的作用&#xff1a; 1.使Java与本地其他类型语言&#xff08;C、C&#xff09;交互&#xff1b; 2.在Java代码调用C、C等语言的代码 或者 C、C调用Java代码。 由于JAVA具有跨平台的特点&#xff0c;所以JAVA与本地代码的交互能力弱&#xff0c;采用JNI特性可以增强JA…...

CSS 高频按钮样式

矩形与圆角按钮 正常而言&#xff0c;我们遇到的按钮就这两种 -- 矩形和圆角&#xff1a; 它们非常的简单&#xff0c;宽高和圆角和背景色。 <div classbtn rect>rect</div><div classbtn circle>circle</div>.btn {margin: 8px auto;flex-shrink: 0;…...