【Java核心能力】编程功底-设计模式之策略模式

news2024/10/7 18:24:39

欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!

在我后台回复 「资料」 可领取编程高频电子书
在我后台回复「面试」可领取硬核面试笔记

文章导读地址:点击查看文章导读!

感谢你的关注!

编程功底-设计模式之策略模式

策略模式在项目中是比较常用的,主要作用是 可以从实现同一个功能的多种方式中选择其中一种进行实现 ,比如说在 RPC 通信中,有多种不同的通信协议如 Dubbo、HTTP、自定义协议等等,那就需要不同的解析算法来针对不同协议进行解析,在具体调用的时候,就需要根据不同的协议来选择不同的协议解析算法,这就可以使用到策略模式

策略模式其他的应用场景还有许多,比如使用优惠券,有不同的优惠策略,那么就需要多种优惠计算实现,使用时再根据具体的优惠策略选择其中一种算法实现

使用策略模式的好处就是:

1、可以根据不同场景切换不同实现策略

2、可以消除代码中的 if-else 代码块

策略模式的结构

image-20240407213834403

如上图,策略模式主要包含 3 种角色:

1、Context: Context 主要维护一个对抽象策略类的引用,这个引用可以指向不同的具体实现策略

2、Strategy: 抽象策略类,所有具体实现策略类的抽象父类

3、ConcreteStrategyA、ConcreteStrategyA: 具体实现策略,集成抽象策略父类,定义具体的实现策略

接下来先根据上边 UML 类图写出一版代码,如下:

// Context 类
public class Context {
    private AbstractStrategy strategy;
    public void setStrategy(AbstractStrategy strategy) {
        this.strategy = strategy;
    }
    public void resolve() {
        strategy.resolve();
    }

    public static void main(String[] args) {
        Context context = new Context();
        context.setStrategy(new DubboStrategy());
        context.resolve();
    }
}
// 抽象策略父类
public abstract class AbstractStrategy {
    public abstract void resolve();
}
// 具体策略实现类
public class DubboStrategy extends AbstractStrategy {
    @Override
    public void resolve() {
        System.out.println("Dubbo协议解析");
    }
}
// 具体策略实现类
public class HTTPStrategy extends AbstractStrategy {
    @Override
    public void resolve() {
        System.out.println("HTTP协议解析");
    }
}

结合 Spring 使用策略模式

上边在使用具体策略的时候,我们还需要手动注入策略,这一点不太方便,而且如果新增策略,我们还需要手动去创建新增的策略,来注入到 Context 中才可以进行使用,因此接下来通过 Spring 进一步对策略模式进行完善,通过 Spring 提供的扩展点 InitializingBean 来扫描创建所有的实现策略,当需要使用时,直接根据 type 来获取对应的实现策略即可

做出优化为:将 Context 类给去掉,换为 ProtocolStrategyFactory 抽象策略工厂,通过策略工厂返回我们需要的策略

UML 类图如下:

image-20240408153347398

代码如下:

// 抽象策略工厂,实现了 InitializingBean,这个是 Spring 提供的扩展点:afterPropertiesSet(),在该方法在扫描所有的具体策略类,注入到 protocolStrategys 属性中
@Component
public class ProtocolStrategyFactory implements InitializingBean {
    private final Map<String, AbstractStrategy> protocolStrategys = new HashMap<>();
    @Autowired
    private ApplicationContext applicationContext;

   public AbstractStrategy getStrategy(String type) {
        return protocolStrategys.get(type);
   }

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, AbstractStrategy> strategys = applicationContext.getBeansOfType(AbstractStrategy.class);
        strategys.forEach((k, v) -> protocolStrategys.put(v.type(), v));
    }
}

// 抽象策略类,这里替换为接口实现,因为 Java 可以单继承、多实现,因此能用接口尽量用接口,将继承的机会省出来
public interface ProtocolStrategy {
    public void resolve();
    public String type();
}


// 具体策略类
@Component
public class DubboStrategy implements ProtocolStrategy {
    @Override
    public void resolve() {
        System.out.println("Dubbo协议解析");
    }

    @Override
    public String type() {
        return "Dubbo";
    }
}
// 具体策略类
@Component
public class HTTPStrategy implements ProtocolStrategy {
    @Override
    public void resolve() {
        System.out.println("HTTP协议解析");
    }

    @Override
    public String type() {
        return "HTTP";
    }
}
// 测试类
@SpringBootTest
class SpringBootProApplicationTests {
    @Autowired
    private ProtocolStrategyFactory protocolStrategyFactory;

    @Test
    void contextLoads() {
        AbstractStrategy dubbo = protocolStrategyFactory.getStrategy("Dubbo");
        dubbo.resolve();
    }
}

这样在新增策略的时候,只需要新增具体的实现策略,工厂会自动取扫描所有的实现策略,并且进行保存,如果不基于 Spring 的扩展点来做的话,当新增策略时需要手动将新增策略放入工厂中,违反了 开闭原则

因此策略模式和 Spring 结合使用,让开发者可以很方便的获取实现策略,并且新增策略也不会违反开闭原则

开发者获取实现策略时,直接根据 type 去工厂中获取对应的实现策略即可,这里的 type 可以使用常量给抽取出来,这里为了看起来方便,没有进一步抽取

策略模式优点

项目中引入策略模式,优点如下:

1、抽象策略与具体实现策略分离,利用继承和多态来管理多个策略类,优化代码结构

2、避免大量使用 if else,如果没有策略模式对具体策略统一管理,那么每新增一个策略模式,都要根据条件进行 if 判断,决定使用哪一个具体策略;有了策略模式之后,就可以将 type 标识传入策略工厂,让工厂返回一个具体实现策略

3、提升代码复用性,将具体实现策略抽取出来,可以在不同环境中进行复用

4、可以很方便的切换实现策略,只需要指定要用到的策略即可,其余工作都由策略工厂来完成

最后总结一下,通过策略模式,在不修改原有代码的基础上可以选择使用不同的策略,并且可以灵活的增加新的

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

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

相关文章

最长公共子序列(线性dp)-java

本文主要来描述两个字符串的最长公共子序列问题 文章目录 前言 一、最长公共子序列 二、算法思路 1.dp[i][j]的四种情况 2. dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1]的关系 3.dp数组的状态转移方程 4.dp数组具体如下 三、代码如下 1.代码如下&#xff08;示例&#xff09;&#x…

Linux shell编程学习笔记46:awk命令的由来、功能、格式、选项说明、版权、版本

0 前言 在编写Linux Shell脚本的过程中&#xff0c;我们经常要对Linux命令执行的结果进行分析和提取&#xff0c;Linux也在文本分析和提取这方面提供了不少的命令。比如我们之前研究过的cut命令。 Linux shell编程学习笔记43&#xff1a;cut命令https://blog.csdn.net/Purple…

【LeetCode】手撕系列—82. 删除排序链表中的重复元素 II

目录 1- 思路2- 题解⭐删除排序链表中的重复元素 II——题解思路 3- ACM模式 原题链接&#xff1a;82. 删除排序链表中的重复元素 II 1- 思路 定义虚拟头结点 定义 cur 指针&#xff0c;cur指针始终指向虚拟头结点&#xff0c;依此操作 cur.next 和 cur.next.next while条件为…

无线游戏手柄的测试(Windows11系统手柄调试方法)

实物 1、把游戏手柄的无线接收器插入到电脑usb接口中 2、【控制面板】----【查看设备和打印机】 3、【蓝牙和其它设备】--【更多设备和打印机设置】 4、鼠标右键【游戏控制器设置】 5、【属性】 6、【测试】&#xff08;每个按键是否正常&#xff09; 7、【校准】&#xff08;…

微信自动回复这样设置,让你的沟通更加高效便捷!

面对繁忙的生活和不断涌入的信息&#xff0c;我们往往无法及时回复微信好友的消息&#xff0c;这给沟通带来了一定的困扰。有没有一种方法能够让我们在忙碌的同时&#xff0c;依然能够及时回复好友并提高沟通效率呢&#xff1f; 答案是肯定的&#xff01;我们可以通过微信管理…

智能传真机触摸屏中应用的触摸感应芯片

智能传真机是应用扫描和光电变换技术&#xff0c;把文件、图表、照片等静止图像转换成电信号&#xff0c;传送到接收端&#xff0c;以记录形式进行复制的通信设备。智能传真机将需发送的原件按照规定的顺序&#xff0c;通过光学扫描系统分解成许多微小单元&#xff08;称为像素…

配置交换机 SSH 管理和端口安全

实验1:配置交换机基本安全和 SSH管理 1、实验目的 通过本实验可以掌握&#xff1a; 交换机基本安全配置。SSH 的工作原理和 SSH服务端和客户端的配置。 2、实验拓扑 交换机基本安全和 SSH管理实验拓扑如图所示。 3、实验步骤 &#xff08;1&#xff09;配置交换机S1 Swit…

Linux:文本编辑器 - vim

Linux&#xff1a;文本编辑器 - vim vim基本操作普通模式模式切换移动光标复制粘贴删除替换撤销 底行模式行号查找 vim基本操作 Vim(Vi Improved)是一款功能强大的文本编辑器&#xff0c;是Unix/Linux系统中广泛使用的编辑器之一。它源于上世纪70年代开发的Vi编辑器&#xff0…

初识--数据结构

什么是数据结构&#xff1f;我们为什么要学习数据结构呢....一系列的问题就促使我们不得不了解数据结构。我们不禁要问了&#xff0c;学习C语言不就够了吗&#xff1f;为什么还要学习数据结构呢&#xff1f;这是因为&#xff1a;数据结构能够解决C语言解决不了的问题&#xff0…

数据结构和算法:回溯

回溯算法 回溯算法&#xff08;backtracking algorithm&#xff09;是一种通过穷举来解决问题的方法&#xff0c;它的核心思想是从一个初始状态出发&#xff0c;暴力搜索所有可能的解决方案&#xff0c;当遇到正确的解则将其记录&#xff0c;直到找到解或者尝试了所有可能的选…

spring-cloud微服务openfeign

Spring Cloud openfeign对Feign进行了增强&#xff0c;使其支持Spring MVC注解&#xff0c;另外还整合了Ribbon和Nacos&#xff0c;从而使得Feign的使用更加方便 优势&#xff0c;openfeign可以做到使用HTTP请求远程服务时就像洞用本地方法一样的体验&#xff0c;开发者完全感…

unity学习(83)——细节名称和血条

眼中有细节&#xff0c;学习的过程才能平稳&#xff01; 1.游戏更新时把名字也更新 代码如下&#xff1a; 效果如下&#xff1a; 2.因为是第三人称&#xff0c;从背后看&#xff0c;所以名称应该水平对称&#xff0c;翻转一下&#xff01;rotate y180 游戏内效果如下&#xf…

IEC101、IEC103、IEC104、Modbus报文解析工具

一、概述 国际电工委员会第57技术委员会&#xff08;IEC TC57&#xff09;1995年出版IEC 60870-5-101后&#xff0c;得到了广泛的应用。为适应网络传输&#xff0c;2000年IEC TC57又出版了IEC 60870-5-104&#xff1a;2000《远东设备及系统 第5-104部分&#xff1a;传输规约-采…

【数据交换格式】网络socket编程温度采集智能存储与上报项目技术------JSON、TLV

作者简介&#xff1a; 一个平凡而乐于分享的小比特&#xff0c;中南民族大学通信工程专业研究生在读&#xff0c;研究方向无线联邦学习 擅长领域&#xff1a;驱动开发&#xff0c;嵌入式软件开发&#xff0c;BSP开发 作者主页&#xff1a;一个平凡而乐于分享的小比特的个人主页…

数据结构__顺序表和单链表

顺序表的改进 问题&#xff1a; 1. 中间/头部的插入删除&#xff0c;时间复杂度为O(N) 2. 增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗。 3. 增容一般是呈2倍的增长&#xff0c;势必会有一定的空间浪费。例如当前容量为100&#xff0c;满了…

安卓逆向 | 某X游戏垂类Web nonce

*本案例仅做分析参考,如有侵权请联系删除 1.逻辑分析 通过XHR断点,然后逐步往上调发现nonce生出处。 在console执行下函数 其中 i,是当前日期和时间的秒级时间戳,并将其向下取整到最接近的整数。 i = ~~(+_.w() / 1e3)w</

CLI举例:上下行连接路由器(路由引流)

CLI举例&#xff1a;上下行连接路由器&#xff08;路由引流&#xff09; 介绍了集群设备&#xff0c;上下行连接路由器的配置举例。 组网需求 如图1所示&#xff0c;上行网络使用BGP&#xff0c;下行网络使用OSPF&#xff0c;多数据中心统一通过路由器R4接入Internet。 希望…

C++位图和布隆过滤器(含哈希切割)

文章目录 C位图和布隆过滤器&#xff08;含哈希切割&#xff09;1、位图&#xff08;Bitmap&#xff09;1.1、位图的概念1.2、位图的使用1.3、位图的模拟实现1.4、位图相关面试题 2、布隆过滤器&#xff08;Bloom Filter&#xff09;2.1、布隆过滤器的概念2.2、布隆过滤器的插入…

【通信原理笔记】【三】模拟信号调制——3.5 角度调制(FM、PM)与其频谱特性

文章目录 前言一、相位与频率二、PM和FM的数学表示三、FM的频谱四、FM信号的带宽——卡松公式总结 前言 在之前介绍的几种调制方式中&#xff0c;我提到信噪比时计算的是用户解调后的信噪比&#xff0c;然而在北邮通信原理课中考虑的是解调器输入的信噪比&#xff0c;即考虑的…

一键破解WB多条带--Swissprot数据库

WB条带不符合预期&#xff1f; 不要着急扔掉结果&#xff0c;有可能是重要信息忽略了哟&#xff01;Swissprot带你了解蛋白大小的前因后果。 UniProtKB/Swiss-Prot (reviewed) 是一个高质量人工注释且非冗余的蛋白序列数据库。其中包含各类实验结果、计算得到的特征信息和文献…