Java中的策略模式

news/2024/10/7 18:36:29/文章来源:https://www.cnblogs.com/dwcg/p/18175381

Java中的策略模式

综述

本文总结了策略模式的定义,特点,使用场景以及实现思路。

策略模式的定义

策略模式说通了, 就是定义一系列的算法, 将它们各自封装起来, 并且使用一个共同的接口使它们可相互替换. 使得算法和算法之间没有耦合, 这样如果方法需要修改或者添加, 工程师不需要修改那些无关的算法. 特别是当业务逻辑需要从多种算法之中挑选自己需要的算法时, 采用策略模式会非常的有效.

策略模式的特点和使用场合

策略模式主要使用场景在于将业务代码和具体算法进行解耦. 当某个业务代码需要用到某种算法来实现这个功能, 且不能保证未来一直永这类算法, 并共用同一个接口, 这时候就可以考虑策略模式. 常见的使用场景包括排序算法、缓存策略、支付方式等等

策略模式有以下优点:

  • 对算法或行为进行封装, 方便开发和理解.
  • 切换方便, 扩展也方便.

当然策略模式也有缺点, 策略模式为了将算法和业务模式解耦, 额外添加了类的数量以及代码量. 所以在算法数量较少的时候(特别是干脆只有一种算法的时候)不建议采用策略模式, 避免出现杀鸡用牛刀空耗时间与精力.

策略模式的实现思路

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

  • 上下文(Context):维护一个对策略对象的引用,负责将客户端请求委派给具体的策略对象执行。上下文类可以通过依赖注入、简单工厂等方式来获取具体策略对象。
  • 抽象策略(Abstract Strategy):定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法。
  • 具体策略(Concrete Strategy):实现了抽象策略定义的接口或抽象类,包含了具体的算法实现。

如果读者熟悉状态模式的话就会发现二者非常的相似, 因为状态模式的核心角色分别是 上下文 抽象状态和具体状态. 可以发现这两个模式在很多地方有类似之处, 这也是为什么很多开发者会选择用策略模式替代状态模式的原因. 但是两者仍然存在一些本质上的不同.
对于状态模式而言, 状态的切换应该是固定的, 切换顺序根据不同的实现思路应该内置于具体状态或者上下文之中. 而策略模式中不同的状态切换是外置的, 是可以交由context的实例的调用者根据需要以任意切换的.

策略模式示例

下面展示一个有足够泛用性示例, 策略模式同时还结合了工厂模式, 实际使用的时候还可以结合单例模式但是此处就不再继续拓展了

首先是 AbstractStrategy 接口, 这里内部的方法叫什么不重要, 重要的是所有策略都需要实现同样的方法, 既所有的策略必须接收同样的参数, 或者不接收任何参数, 当然如果不同的策略实际用到的参数不一样, 可以使用最大集构建一个接收所有参数的execute(para...) 方法, 这样用到哪个参数就调用哪个参数, 用不到就忽略

public interface AbstractStrategy {void execute();
}

然后是 AbstractStrategy 的各种实现类, 既单独的策略

public class FooBarConcreteStrategy implements AbstractStrategy{@Overridepublic void execute() {//在真实的使用时可以在方法中进行任意操作, //此处只使用打印文字作为举例, 下同System.out.println("foobar");}
}public class HelloWorldConcreteStrategy implements AbstractStrategy{@Overridepublic void execute() {System.out.println("hello, world");}
}

然后是context类

public class ExecuteContext {private AbstractStrategy strategy;// 设置策略public void setStrategy(AbstractStrategy strategy) {this.strategy = strategy;}// 执行策略public void executeStrategy() {strategy.execute();return;}
}

最后是一个调用的示例, 实际使用的时候当然要放在具体的方法中

public class StrategyPattern {public static void main(String[] args){ExecuteContext context = new ExecuteContext();context.setStrategy(new HelloWorldConcreteStrategy());context.executeStrategy();}
}

策略模式拓展版本

因为纯策略模式要求调用者熟悉当前需要测策略, 在易用性方面不够友好, 所以这里给出一个策略模式+简单工厂模式的拓展版本

相较于原来的策略模式, 修改context, 这里context同时还承担了factory的职责, 所以核心是STRATEGY_MAP, 用于对外返回需要的策略实例. 同时内置一个public类型的内部枚举类, 这样外部调用策略实例的时候可以通过枚举类的提示知道当前提供哪几种策略. 具体如下

public class ExecuteContextExtension {private static final Map<ExecuteStrategyName, AbstractStrategy> STRATEGY_MAP = new HashMap<>();static {STRATEGY_MAP.put(ExecuteStrategyName.HelloWorld, new HelloWorldConcreteStrategy());STRATEGY_MAP.put(ExecuteStrategyName.FooBar, new FooBarConcreteStrategy());}public AbstractStrategy getStrategy(ExecuteStrategyName name){return STRATEGY_MAP.get(name);}public enum ExecuteStrategyName {HelloWorld,FooBar,}
}

调用的写法为

public class StrategyPattern {public static void main(String[] args){ExecuteContextExtension factory = new ExecuteContextExtension();AbstractStrategy foobarStrategy = factory.getStrategy(ExecuteStrategyName.FooBar);foobarStrategy.execute();
}

其余不变
这一拓展的好处在于, 对于调用者而言它可以直接从context内置的枚举类中知道整个模块提供了哪几种策略. 易用性拉满, 当然缺点是对开闭原则的支持没有纯策略模式那么好.

总结

策略模式是23种设计模式中的一种, 属于行为模式这一细分类别, 主要用于解耦业务逻辑和具体算法. 个人以为, 策略模式属于和观察者模式以及工厂模式同一级别的标杆级设计模式, 构思精妙, 威力强大, 应用广泛. 当然和单例模式这种简单易行的模式不同, 也就没有速成之法, 新手从接触到上手总还是要半天时间.

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

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

相关文章

React 中的 diff 算法

React diff为什么使用虚拟 DOM ? 浏览器在处理 DOM 的时候会很慢,处理 JavaScript 会很快,页面复杂的时候,频繁操作 DOM 会有很大的性能开销(每次数据变化都会引起整个 DOM 树的重绘和重排)。 为了避免频繁操作 DOM,React 会维护两个虚拟 DOM,如果有数据更新,会借此计…

20222315 2024-2025-1 《网络与系统攻防技术》实验一实验报告

1.实验内容 1.掌握反汇编与十六进制编程器 2.能正确修改机器指令改变程序执行流程 3.能正确构造payload进行bof攻击 2.实验过程 1.直接修改程序机器指令,改变程序执行流程 将pwn1文件下载至kali中并将pwn1文件改名为pwn20222315,并将其内容复制到pwn2反汇编文件objdump -d…

多校A层冲刺NOIP2024模拟赛03

多校A层冲刺NOIP2024模拟赛03\(T1\) A. 五彩斑斓(colorful) \(90/100pts\)部分分\(20pts\) :枚举左上 \((k,h)\) 、右下端点 \((i,j)\) ,时间复杂度为 \(O(n^{2}m^{2})\) 。 \(90/100pts\) :当 \(a_{i,j} \ne a_{k,j}\) 时任意的 \(h \in [1,j]\) 都符合题意、不妨钦定 \(…

Word中 Endnote 引用标蓝色

1. 打开word中的endnote加载项。如图所示,勾选这两个设置。 确认后会自动变为超链接,显示蓝色以及下划线。 2. 在样式设置中,将超链接的下划线取消。之后就会只显示蓝色引用。 结果显示:

中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1)

中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1) Problem A. 贵校是构造王国吗 I 思路 官方题解很清晰明了。代码 #include <bits/stdc++.h> using namespace std; #define int long long #define endl \n #define PII pair&…

多校 A 层冲刺 NOIP2024 模拟赛 03

多校 A 层冲刺 NOIP2024 模拟赛 03 T1 五彩斑斓(colorful) 签到题 直接暴力枚举是 \(O(n^4)\) ,考虑使用 \(bitset\) 优化,对每个点开个 \(bitset\),预处理它所在一行它及它之前相同颜色的位置,这样就只用枚举另一个点所在列,时间复杂度为 \(O(n^3+\frac{n^4}{w})\)。 T…

在浏览器上访问媒体资源配置【文件上传】

1.根urls.py文件中 from django.contrib import admin from django.urls import path, include, re_path from django.views.static import serve from django.conf import settingsurlpatterns = [# path(admin/, admin.site.urls),path(api/shipper/, include(apps.shipper.u…

高级程序语言设计第二次作业

姓名:袁志华 班级:软件工程2班 学号:102400231 班级网址:https://edu.cnblogs.com/campus/fzu/2024C 作业网址:https://edu.cnblogs.com/campus/fzu/2024C/homework/13282 图片: 第一题: 第二题: 第三题: 第四题: 第五题: 第六题: 第七题: 第八题:程序清单: 3.1…

macOS Sequoia 15.0.1 (24A348) 正式版 ISO、IPSW、PKG 下载

macOS Sequoia 15.0.1 (24A348) 正式版 ISO、IPSW、PKG 下载macOS Sequoia 15.0.1 (24A348) 正式版 ISO、IPSW、PKG 下载 iPhone 镜像、Safari 浏览器重大更新和 Apple Intelligence 等众多全新功能令 Mac 使用体验再升级 请访问原文链接:https://sysin.org/blog/macOS-Sequoi…

人群聚集监测预警系统

人群聚集监测预警系统采用AI视频智能分析技术,人群聚集监测预警系统通过在工地、工厂等场所已经安装监控摄像头,人群聚集监测预警系统对人员聚集情况进行实时监测,当人群聚集过于密集时,系统将自动发出警报,人群聚集监测预警系统并通过人工智能算法对人员的状态进行识别和…

智能烟火识别预警软件

智能烟火识别预警软件采用人工智能技术,智能烟火识别预警软件在工厂、工地等场所利用已经安装的摄像头,智能烟火识别预警软件对场内的烟花爆竹进行实时监测。当场内出现烟花爆竹时,智能烟火识别预警软件将自动发出警报,并通过人工智能算法通知现场管理人员进行处理。智能烟…

脱岗监测预警系统

脱岗监测预警系统可以通过对工人的位置进行实时监测,脱岗监测预警系统识别是否存在脱岗行为,并及时发出警报。脱岗监测预警系统在工作过程中,如果工人离开其工作位置,脱岗监测预警系统会自动识别并发出警报,提醒管理人员采取措施防止事故的发生。脱岗监测预警系统可以通过…