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

设计模式之策略模式实践

设计模式之策略模式实践

先了解一下策略模式的定义是什么?解决什么问题

策略模式是一种行为设计模式,它定义了一系列算法,将每个算法封装成一个类,并使它们可以互相替换。策略模式允许客户端在运行时从可互换的算法中选择一个,而不必修改使用它们的代码。这模式提供了一种将算法独立于客户端而变化的方式。

策略模式主要包含以下几个角色:

  1. Context(上下文): 持有一个策略对象的引用,负责将具体的算法委托给策略对象执行。
  2. Strategy(策略): 定义了一个算法族的接口,所有具体策略类都必须实现该接口。这个接口通常只包含一个方法,即算法的执行方法。
  3. ConcreteStrategy(具体策略): 实现了策略接口的具体算法类。每个具体策略类都封装了一个特定的算法。

使用场景:

  • 当一个系统中有许多类,它们之间的区别仅在于它们的行为时,可以使用策略模式,将行为抽象为一个接口,然后为每个具体行为实现一个策略类。
  • 当一个类定义了多种行为,并且这些行为在该类的操作中以多个条件语句的形式出现时,可以考虑使用策略模式,将每个条件分支的实现封装到具体策略类中。
  • 当一个系统需要动态地在几种算法中选择一种时,可以使用策略模式,使得客户端可以根据需要切换算法。

策略模式的优点包括:

  • 提供了一种替代继承的方式,避免了使用多重条件语句来选择算法。
  • 将算法的实现细节与客户端分离,使得算法的变化不会影响到使用算法的客户端。

总之,策略模式使得算法的变化独立于使用算法的客户端,提高了系统的灵活性和可维护性。

理论讲完了进入正题👇

实践

当我们学习完设计模式的时候,是不是总是想不出如何将设计模式运用到自己的项目中,那么下面就使用一个我在项目中遇到的问题,并使用设计模式对代码进行优化

简单功能介绍:项目有一个每日领取积分的功能,想根据不同的用户身份每日领取不同的积分

在这里插入图片描述

每日领取积分(未优化前)

ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
// 查询当前用户今日是否已经获取
QueryWrapper<RewardRecord> qw = new QueryWrapper<>();
Long userId = loginUser.getId();
LocalDateTime now = LocalDateTime.now();
List<RewardRecord> rewardRecords = rewardRecordMapper.judgeTodayHasAdd(userId, now);
if (!rewardRecords.isEmpty()) {throw new BusinessException(ErrorCode.OPERATION_ERROR, "今日已领取");
}
RewardRecord rewardRecord = new RewardRecord();
rewardRecord.setRewardPoints(RewardRecordConstant.DAY_FREE_NUM);
rewardRecord.setUserId(loginUser.getId());
boolean save = this.save(rewardRecord);
ThrowUtils.throwIf(!save, ErrorCode.SYSTEM_ERROR);
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
// 获取积分
userUpdateWrapper.eq("id", loginUser.getId()).setSql("totalRewardPoints = totalRewardPoints + " + RewardRecordConstant.DAY_FREE_NUM);
boolean update = userService.update(userUpdateWrapper);
ThrowUtils.throwIf(!update, ErrorCode.SYSTEM_ERROR);
return true;

原来领取的积分是写死的,现在有个新的需求,VIP每日可以获取20积分, SVIP每日可以获取40积分

想要实现上面的需求,怎么做?

大部分人下意识想到下面的实现方法

User user = getUserInfo();
if(user == 用户) {// ...
} else if(user == vip) {// ...
} else if(user == svip) {//...
}

难道我们要写这么多的if else吗?假如我之后还要加另外的角色呢?再往上面写if else吗?那就不太体面

其实我们完全可以使用策略模式,策略模式其实就是用来优化这种多分支情况

不同的情况对应不同的处理策略

话不多说,我们以上面每日领取积分的案例看一下策略模式怎么应用上

在这里插入图片描述

  1. 首先我们要定义一个写一个策略的接口(RoleService),每一个策略实现类都要实现这个策略接口

    /*** @Author:HWQ* @DateTime:2023/11/13 20:31* @Description: 角色策略接口**/
    public interface RoleService {/*** 判断是否是当前角色* @return*/boolean isCurrentRole(String userType);/*** 获取每日积分的数量* @return*/Integer getDayReward();/*** 获取最大的Token数* @return*/Integer getMaxToken();/*** 获取图表保存天数* @return*/Integer getChartSaveDay();/*** 获取对话保存信息* @return*/Integer getChatSaveDay();
    }
    
  2. 编写策略实现类

    // 普通用户
    @Service
    public class NormalUserService implements RoleService {@Overridepublic boolean isCurrentRole(String userType) {ThrowUtils.throwIf(StringUtils.isEmpty(userType), ErrorCode.PARAMS_ERROR);return UserRoleEnum.USER.getValue().equals(userType);}@Overridepublic Integer getDayReward() {return 10;}@Overridepublic Integer getMaxToken() {return 2048;}@Overridepublic Integer getChartSaveDay() {return 10;}@Overridepublic Integer getChatSaveDay() {return 10;}
    }
    
    // vip用户
    @Service
    public class VIPUserService implements RoleService {@Overridepublic boolean isCurrentRole(String userType) {ThrowUtils.throwIf(StringUtils.isEmpty(userType), ErrorCode.PARAMS_ERROR);return UserRoleEnum.VIP.getValue().equals(userType);}@Overridepublic Integer getDayReward() {return 20;}@Overridepublic Integer getMaxToken() {return 2048;}@Overridepublic Integer getChartSaveDay() {return 30;}@Overridepublic Integer getChatSaveDay() {return 30;}
    }
    
  3. 在需要进行角色判断的地方注入策略Service

在这里插入图片描述

总结:如果你的代码中 if…else 难以维护,可以考虑使用策略模式进行优化

如果你觉得这篇文章对你有帮助,可以关注一下,后续会发更多的设计模式实践案例🫡,Happy coding🚀

相关文章:

设计模式之策略模式实践

设计模式之策略模式实践 先了解一下策略模式的定义是什么&#xff1f;解决什么问题 策略模式是一种行为设计模式&#xff0c;它定义了一系列算法&#xff0c;将每个算法封装成一个类&#xff0c;并使它们可以互相替换。策略模式允许客户端在运行时从可互换的算法中选择一个&a…...

讨论:解决哈希冲突的几种方法

1. 什么是哈希 哈希是通过对数据进行再压缩&#xff0c;提高效率的一种解决方法。 2. 什么时候会产生哈希冲突 通过哈希函数产生的哈希值是有限的&#xff0c;当数据量比较大时经过哈希函数处理后仍然有不同的数据对应相同的值。这时候就产生了哈希冲突。 3. 常见的哈希函数 1&…...

遥感分析时什么情况下需要做大气校正?

经常会遇到这样的问题&#xff1a;什么情况需要做大气校正产生&#xff1f;这个问题取决于传感器和应用目标&#xff0c;总的来说&#xff0c;如果要做光谱分析&#xff0c;那么大气校正是必须要做的。本文对于在什么情况下选择什么样的大气校正方法&#xff0c;给出了一些依据…...

设计模式学习笔记 - 设计原则 - 7.DRY 原则及提高代码复用性

前言 DRY 原则&#xff0c;英文描述为&#xff1a; Don’t Repeat Yourself。中文直译&#xff1a;不要重复自己。将它应用在编程中&#xff0c;可理解为&#xff1a;不要写重读的代码。 可能你认为&#xff0c;这个原则很简单。只要两段代码长得一样&#xff0c;那就是违反 …...

方法的调用

自定函数(方法) 函数(方法): 给定一个具有独立功能的代码片段进行"命名",并通过该该类名调用"方法" main主函数 在当前类中,可以直接调用方法(因为方法使用了static关键字) package study;import java.time.LocalDate; import java.time.format.Date…...

VGW在 Windows 平台上局域网就绪的旁路由器程序

在查阅本篇文章之前可以查看下&#xff0c;本人前两年写的关于VGW软件路由器的文章 Linux 平台上面单网卡 TUN/TAP实现局域网其它设备上网_linux 物理网卡与tun同网段-CSDN博客 VGW软件路由器是一个工作IEEE以太网&#xff08;L2&#xff09;链路层的路由器程序&#xff0c;它…...

能源大数据采集,为您提供专业数据采集服务

随着经济的不断发展&#xff0c;能源产业也逐渐成为国民经济的支柱产业之一。而对于能源行业来说&#xff0c;数据采集是一项至关重要的工作。以往&#xff0c;能源企业采集数据主要依靠人工收集、整理&#xff0c;但是这种方式不仅效率低下&#xff0c;而且容易出现数据不准确…...

01_Maven

文章目录 Maven安装MavenMaven的工作流程配置MavenMaven的使用module和project的关系如何用Maven导包 如何用Maven进行项目构建指令介绍clean指令compile指令package指令install指令 Maven的依赖管理如何导包scope作用域依赖传递依赖冲突 使用Maven开发项目Junit如何使用Junit …...

C语言题目练习

目录 前言 1、转置矩阵 1.1 题目 描述 输入描述&#xff1a; 输出描述&#xff1a; 1.2解题 分析&#xff1a; 程序&#xff1a; 2、KiKi判断上三角矩阵 2.1 题目 描述 输入描述&#xff1a; 输出描述&#xff1a; 2.2 解题 分析&#xff1a; 程序&#xff1a; 3、…...

物联网安全|TrustAsia助力PSWG应对全球物联网产品安全合规挑战

万物互联时代&#xff0c;随着物联网连接数快速增长&#xff0c;物联网设备的潜在网络安全隐患也日益增长&#xff0c;可能导致设备故障、数据被盗、篡改、隐私泄露等问题的发生&#xff0c;甚至成为网络攻击的跳板&#xff0c;对互联网基础设施构成严重威胁。 我们看到&#…...

基于单片机的医院输液系统设计

目 录 摘 要 Ⅰ Abstract Ⅱ 引 言 1 1系统方案设计与论证 3 1.1系统硬件结构总体设计方案 3 1.2点滴速度测量电路方案的选择与论证 3 1.3液面检测电路方案的选择与论证 4 1.4通过电机控制滴速电路的方案与论证 4 1.5显示器接口电路方案选择与论证 5 1.6键盘接口电路方案选择与…...

安卓简单登录

注意 有的朋友不知道登录咋写&#xff0c;这里我就简单给出相应代码&#xff0c;用的本地存储&#xff0c;没用网络请求&#xff0c;有需要可以替换成想要的&#xff0c;废话不多上代码 登录 import androidx.appcompat.app.AppCompatActivity;import android.content.Context…...

【计算机网络】DNS/ICMP协议/NAT技术

文章目录 一、DNS(Domain Name System)1.DNS背景2.域名3.浏览器中输入url后,发生的事情 二、ICMP协议1.什么是ICMP协议2.ICM功能3.ICMP的报文格式4.ping命令5.traceroute命令 三、NAT技术1.NAT技术背景2.NAT IP转换过程3.NAPT4.NAT技术的缺陷5.NAT和代理服务器 四、TCP/IP五层模…...

2403C++,C++20协程通道

原文 通道是一个可用来连接协程,实现不同协程间通信的并发安全队列. Test fun test know channel() runBlocking<Unit> {val channel Channel<Int>()//生产者val producer GlobalScope.launch {var i 0while (true) {delay(1000)channel.send(i)println("…...

C语言从入门到实战——预处理详解

预处理详解 前言一、预定义符号1.1 __FILE__1.2__LINE__1.3 __DATE__1.4__TIME__1.5__STDC__ 二、 #define定义常量三、 #define定义宏四、 带有副作用的宏参数五、 宏替换的规则六、宏函数的对比七、 #和##7.1 #运算符7.2 ##运算符 八、 命名约定九、 #undef十、命令行定义十一…...

【LabVIEW FPGA】CIC滤波器

一、CIC滤波器应用概述 在通信数字信号上下变频时&#xff0c;经常会用到对数字信号的升采样和降采样&#xff0c;即通过CIC数字速率器实现变采样率。 二、滤波器IP 首先设置滤波器基本参数&#xff08;filter specification&#xff09; 滤波器类型&#xff08;Filter Type…...

砝码称重 蓝桥杯

在C中&#xff0c;fabs()和abs()都用于计算数字的绝对值&#xff0c;但它们之间有一些区别。 fabs(double x)&#xff1a;计算浮点数x的绝对值&#xff0c;返回一个double类型的结果。 abs(int x)&#xff1a;计算整数x的绝对值&#xff0c;返回一个int类型的结果。 数组的默…...

AmzTrends x TiDB Serverless:通过云原生改造实现全局成本降低 80%

本文介绍了厦门笛卡尔数据&#xff08;AmzTrends&#xff09;在面临数据存储挑战时&#xff0c;选择将其数据分析服务迁移到 TiDB Serverless 的思路和实践。通过全托管的数据库服务&#xff0c;AmzTrends 实现了全局成本降低 80% 的效果&#xff0c;同时也充分展示了 TiDB Ser…...

[最佳实践] Windows上构建一个和Linux类似的Terminal

感谢大佬批评指正&#xff0c;现已更新 preview Target&#xff1a;致力打造最赏心悦目Window下的终端&#xff0c;同时能够很接近Linux的使用习惯 key word&#xff1a;windows终端美化 windows terminal windows powershell 类似Linux下的Window终端 Window也能用ll windows…...

租赁系统|手机租赁软件|租赁系统功能开发

当如今的生活用品越来越多、交流更加便捷时&#xff0c;人们的消费需求也变得越来越丰富。不可避免地&#xff0c;我们会遇到这样一种情况&#xff1a;需要新的手机&#xff0c;但资金有限。此时&#xff0c;手机租赁小程序呼之欲出。这种创意不仅使我们能够充分利用各类闲置物…...

【设计模式 04】建造者模式

如果要构建的对象很复杂&#xff0c;那么可以将整个构建过程拆分成多个步骤&#xff0c;并为每一个步骤定义一个抽象的接口。并添加一个指导者用来控制构建产品的顺序和步骤。 Java实现&#xff1a; // 产品类 class Product {private String part1;private String part2;pub…...

Python使用错误总结

【1】cannot import name ‘ParameterSource’ from ‘click.core’ 其根本原因在于是black模块&#xff0c;其模块版本可能过时&#xff0c;升级black模块版本即可&#xff1a; pip install black --upgrade【2】partially initialized module ‘charset_normalizer’ has n…...

【Java EE初阶三十】JVM的简单学习

1. JVM 内存区域划分 一个运行起来的 Java 进程&#xff0c;就是一个 JVM 虚拟机&#xff0c;需要从操作系统申请一大块内存&#xff0c;就会把这个内存&#xff0c;划分成不同的区域&#xff0c;每个区域都有不同的作用. JVM 申请了一大块内存之后,也会划分成不同的内…...

thinkphp5水平分割表partition,以及查询操作

前言 先交代下背景,在一个项目中,有一个数据表有水平分表的需求。当时想找到一种方法&#xff0c;把对数据库的操作&#xff0c;写到一个模型里&#xff0c;通过去换模型属性中的table来达到代码不变操作的数据表变化的效果。 我们都知道&#xff0c;模型要想关联数据表的话&a…...

docker部署aria2-pro

前言 我平时有一些下载视频和一些资源文件的需求&#xff0c;有时候需要离线下载&#xff0c;也要速度比较快的方式 之前我是用家里的玩客云绝育之后不再写盘当下载机用的&#xff0c;但是限制很多 我发现了aria2 这个下载器非常适合我&#xff0c;而有个大佬又在原来的基础…...

vue中Mixins

使用 Mixins 的主要优点包括&#xff1a; 代码复用: 可以将常用的逻辑封装在 Mixin 中&#xff0c;然后在多个组件中重复使用。逻辑分离: 将不同功能的代码分开管理&#xff0c;使代码更加清晰和易于维护。灵活性: Mixins 允许你在组件中引入多个 Mixin&#xff0c;并且可以根…...

linux常用指令(定期更新)

linux常用指令 1.页相关页大小 2.系统参数3.启动参数4.网络参数查询网卡所属numa节点信息网络测速相关iperf测试sar监控网卡流量查看网卡txqueuelen和mtu抓包tcpdump 网络数据收发状态snmp协议栈netstat -i所有网口TX-OK、RX-OKnetstat-s查看各个协议的收发数据ethtool -S单个网…...

【项目】图书管理系统

目录 前言&#xff1a; 项目要求&#xff1a; 知识储备&#xff1a; 代码实现&#xff1a; Main&#xff1a; Books包&#xff1a; Book&#xff1a; BookList&#xff1a; Operate包&#xff1a; Operate: addOperate: deleteOperate: exitOperate: findOperate:…...

华为OD机试 - 疫情扩散时间计算 - 矩阵(Java 2024 C卷 200分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&am…...

[数据集][图像分类]棉花叶子病害分类数据集2293张4类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;2293 分类类别数&#xff1a;4 类别名称:["diseased_cotton_leaf"…...