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

策略模式终极解决方案之策略机

我们在开发时经常会遇到一堆的if else …, 或者switch, 比如我们常见的全局异常处理等, 像类似这种很多if else 或者多场景模式下, 策略模式是非常受欢迎的一种设计模式, 然而, 一个好的策略模式却不是那么容易写出来.

我在工作中也因为写烦了switch,if else 觉得很不优雅, 因此,我考虑是否有一套统一的解决方案呢?

思考我问题的初衷, 在什么策略下, 满足什么条件执行什么动作, 返回什么值, 这就是策略模式需要解决的核心问题, 大眼一看好似有点类似状态机? 然而它并不是状态机, 状态机是比较笨重, 而策略机应该是足够轻量的.

我们再来看核心问题,关于什么策略,满足什么条件执行什么动作,返回什么值, 是一个明显的dsl语法, 因此, 我的基本语法糖已确立: strategy.of().when().perform()或者strategy.of().perform(), 因为有时我们并不需要条件, 仅仅策略即可.

我们要实现上述语法糖, 就得设计一套规则, 使其可以满足dsl, 并且是合理的, 如此, 基本定义已确定, 如下:

/*** {@link StrategyMachineBuilder}* @param <S> strategy* @param <C> context* @param <R> result*/
public interface StrategyMachineBuilder<S,C,R> {Of<S,C,R> of(S s);StrategyMachine<S,C,R> build(String id);
}
/*** {@link Of}* @param <S> strategy* @param <C> context* @param <R> result*/
public interface Of<S,C,R> {When<S,C,R> when(Condition<S,C,R> condition);StrategyMachineBuilder<S,C,R> perform(Action<C,R> action);
}
/*** {@link When}* @param <S> strategy* @param <C> context* @param <R> result*/
public interface When<S,C,R> {StrategyMachineBuilder<S,C,R> perform(Action<C,R> action);
}

/*** {@link Condition}* @param <S> strategy* @param <C> context* @param <R> result*/
public interface Condition<S,C,R> {boolean isSatisfied(S s,C c);
}
/*** {@link Action}* @param <C> context* @param <R> result*/
public interface Action<C,R> {R apply(C c);
}
/*** {@link Strategy}* @param <S> strategy* @param <C> context* @param <R> result*/
public interface Strategy<S, C, R> {S strategy();Condition<S,C,R> condition();Action<C, R> action();Strategy<S,C,R> strategy(S s);Strategy<S,C,R> condition(Condition<S,C,R> condition);Strategy<S,C,R> action(Action<C,R> action);
}
/*** {@link StrategyMachine}* @param <S> strategy* @param <C> context* @param <R> result*/
public interface StrategyMachine<S,C,R> {R apply(S s, C c);
}

如此: 架构已经构建完毕, 剩下的工作就很简单了, 实现此架构即可.

/*** {@link StrategyMachineBuilderImpl}* @param <S> strategy* @param <C> context* @param <R> result*/
class StrategyMachineBuilderImpl<S,C,R> implements StrategyMachineBuilder<S,C,R>{private final Map<S, List<Strategy<S,C,R>>> map = new ConcurrentHashMap<>();@Overridepublic Of<S, C, R> of(S s) {map.computeIfAbsent(s, k -> new ArrayList<>());Strategy<S,C,R> strategy = new StrategyImpl();map.get(s).add(strategy);return new OfImpl(strategy);}@Overridepublic StrategyMachine<S, C, R> build(String id) {StrategyMachineImpl<S, C, R> machine = new StrategyMachineImpl<>(map);StrategyCache.put(id, machine);return machine;}public class OfImpl implements Of<S,C,R>{private final Strategy<S,C,R> strategy;OfImpl(Strategy<S,C,R> strategy){this.strategy = strategy;}@Overridepublic When<S, C, R> when(Condition<S,C,R> condition) {this.strategy.condition(condition);return new WhenImpl(strategy);}@Overridepublic StrategyMachineBuilder<S, C, R> perform(Action<C, R> action) {this.strategy.action(action);return StrategyMachineBuilderImpl.this;}}public class WhenImpl implements When<S,C,R> {private final Strategy<S,C,R> strategy;WhenImpl(Strategy<S,C,R> strategy){this.strategy = strategy;}@Overridepublic StrategyMachineBuilder<S, C, R> perform(Action<C, R> action) {this.strategy.action(action);return StrategyMachineBuilderImpl.this;}}public class StrategyImpl implements Strategy<S, C, R> {private S strategy;private Condition<S,C,R> condition;private Action<C, R> action;@Overridepublic S strategy() {return this.strategy;}@Overridepublic Condition<S,C,R> condition() {return this.condition;}@Overridepublic Action<C, R> action() {return this.action;}@Overridepublic Strategy<S, C, R> strategy(S s) {this.strategy = s;return this;}@Overridepublic Strategy<S, C, R> condition(Condition<S,C,R> condition) {this.condition = condition;return this;}@Overridepublic Strategy<S, C, R> action(Action<C, R> action) {this.action = action;return this;}}
}
/*** Strategy Machine Impl* @param <S> strategy* @param <C> context* @param <R> result*/
class StrategyMachineImpl<S,C,R> implements StrategyMachine<S,C,R> {private final Map<S, List<Strategy<S,C,R>>> map;public StrategyMachineImpl(Map<S, List<Strategy<S,C,R>>> map){this.map = map;}@Overridepublic R apply(S s, C c) {List<Strategy<S, C, R>> strategies = map.get(s);if (strategies==null||strategies.isEmpty()){throw new RuntimeException("no strategy found for "+s);}for (Strategy<S, C, R> strategy : strategies) {// 如果没有condition,直接执行actionif (strategy.condition()==null) {return strategy.action().apply(c);}// 如果有condition,先判断是否满足condition,满足则执行actionif (strategy.condition().isSatisfied(s,c)){return strategy.action().apply(c);}}// 未发现策略关于s的conditionthrow new RuntimeException("no strategy found of met condition for "+s);}
}
/*** Strategy Machine Factory*/
public class StrategyMachineFactory {public static <S,C,R> StrategyMachineBuilder<S,C,R> create() {return new StrategyMachineBuilderImpl<>();}public static <S,C,R> StrategyMachine<S,C,R> get(String id) {return (StrategyMachine<S, C, R>) StrategyCache.get(id);}
}
/*** {@link StrategyCache}*/
class StrategyCache {private static final Map<String,StrategyMachine<?,?,?>> CACHE = new java.util.concurrent.ConcurrentHashMap<>();public static void put(String id, StrategyMachine<?,?,?> machine) {CACHE.put(id, machine);}public static StrategyMachine<?,?,?> get(String id) {return CACHE.get(id);}
}

如此, 策略机已实现完毕. 下面给出两种场景例子
一. 不同年龄吃不同分量的药
Example:
Under the age of 12, take 20 milligrams of medication per day;
12-18 years old, taking 30 milligrams a day
18-30 years old, taking 40 milligrams a day
30-50 years old, taking 45 milligrams a day
Eating 42 milligrams for those over 50 years old

class MedicineStrategy {private static StrategyMachine<String, MedicineContext, Void> strategy;static {StrategyMachineBuilder<String, MedicineContext, Void> machineBuilder = StrategyMachineFactory.create();strategy = machineBuilder.of("").when((s, c) -> c.age < 12).perform((c) -> {System.out.println("Under the age of 12, take 20 milligrams of medication per day;");return Void.TYPE.cast(null);}).of("").when((s, c) -> c.age >= 12 && c.age < 18).perform((c) -> {System.out.println("12-18 years old, taking 30 milligrams a day");return Void.TYPE.cast(null);}).of("").when((s, c) -> c.age >= 18 && c.age < 30).perform((c) -> {System.out.println("18-30 years old, taking 40 milligrams a day");return Void.TYPE.cast(null);}).of("").when((s, c) -> c.age >= 30 && c.age < 50).perform((c) -> {System.out.println("30-50 years old, taking 45 milligrams a day");return Void.TYPE.cast(null);}).of("").when((s, c) -> c.age >= 50).perform((c) -> {System.out.println("Eating 42 milligrams for those over 50 years old");return Void.TYPE.cast(null);}).build("medicine");}public static StrategyMachine<String, MedicineContext, Void> get() {// StrategyMachine<String, MedicineContext, Void> strategy = StrategyMachineFactory.get("medicine");return strategy;}@Data@AllArgsConstructor@NoArgsConstructorpublic static class MedicineContext {private int age;}public static void main(String[] args) {get().apply("", new MedicineContext(10));}}

二. 计算机

		StrategyMachineBuilder<String, StrategyContext, Number> machineBuilder = StrategyMachineFactory.create();machineBuilder.of("加法").perform(strategyContext -> strategyContext.a + strategyContext.b);machineBuilder.of("减法").perform(strategyContext -> strategyContext.a - strategyContext.b);machineBuilder.of("乘法").perform(strategyContext -> strategyContext.a * strategyContext.b);// 除法,当c==1时,忽略小数位, 当c==2时不忽略machineBuilder.of("除法").when((s, strategyContext) -> strategyContext.c == 1).perform(strategyContext -> strategyContext.a / strategyContext.b);machineBuilder.of("除法").when((s, strategyContext) -> strategyContext.c == 2).perform(strategyContext -> (strategyContext.a * 1.0d) / (strategyContext.b * 1.0d));StrategyMachine<String, StrategyContext, Number> strategyMachine = machineBuilder.build("test");// StrategyMachine<String, StrategyContext, Number> strategyMachine =  StrategyMachineFactory.get("test");System.out.println(strategyMachine.apply("加法", new StrategyContext(1, 2, 1)));System.out.println(strategyMachine.apply("减法", new StrategyContext(1, 2, 1)));System.out.println(strategyMachine.apply("乘法", new StrategyContext(1, 2, 1)));System.out.println(strategyMachine.apply("除法", new StrategyContext(1, 2, 1)));System.out.println(strategyMachine.apply("除法", new StrategyContext(1, 2, 2)));

源码地址: https://github.com/zhangpan-soft/dv-commons

相关文章:

策略模式终极解决方案之策略机

我们在开发时经常会遇到一堆的if else …, 或者switch, 比如我们常见的全局异常处理等, 像类似这种很多if else 或者多场景模式下, 策略模式是非常受欢迎的一种设计模式, 然而, 一个好的策略模式却不是那么容易写出来. 我在工作中也因为写烦了switch,if else 觉得很不优雅, 因…...

linux 常用指令目录大纲

Linux下的Signal信号处理及详解&#xff0c;test ok-CSDN博客 Linux下怎样判断一个binary是否可以debug//test ok_感知算法工程师的博客-CSDN博客 linux file命令的用法//test ok-CSDN博客 linux下生成core dump方法与gdb解析core dump文件//test ok-CSDN博客 linux readel…...

webpack该如何打包

1.我们先创建一个空的大文件夹 2.打开该文件夹的终端 输入npm init -y 2.1.打开该文件夹的终端 2.2在该终端运行 npm init -y 3.安装webpack 3.1打开webpack网址 点击“中文文档” 3.2点击“指南”在点击“起步” 3.3复制基本安装图片画线的代码 4.在一开始的文件夹下在创建一…...

【STM32】TIM定时器输入捕获

1 输入捕获 1.1 输入捕获简介 IC&#xff08;Input Capture&#xff09;输入捕获 输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff08;上升沿/下降沿&#xff09;&#xff0c;当前CNT的值将被锁存到CCR中&#xff08;把CNT的值读出来&#xff0c;写入到…...

webrtc 设置不获取鼠标 启用回声消除

数 getDisplayMedia()(属于 navigator.mediaDevices 的一部分)与 getUserMedia() 类似,用于打开显示内容(或部分内容,如窗口)。返回的 MediaStream 与使用 getUserMedia() 时相同。 显示鼠标与否 getDisplayMedia() 的约束条件与常规视频或音频输入资源的限制不同。 {…...

JVM虚拟机:如何查看JVM初始和最终的参数?

本文重点 在前面的课程中&#xff0c;我们学习了如何查看当前程序所处于的xx参数&#xff0c;本文再介绍一种如何参看JVM的xx参数&#xff1f; 查看JVM的所有初始化参数 方式一&#xff1a;java -XX:PrintFlagsInitial 方式二&#xff1a;java -XX:PrintFlagsInitial -versio…...

JVM Optimization Learning(五)

目录 一、JVM Optimization 1、G1 1、G1内存模型 2、基础概念 3、G1特点&#xff1a; 4、CMS日志分析 5、G1日志分析 2、GC参数 2.1、GC常用参数 2.2、Parallel常用参数 2.3、CMS常用参数 2.4、G1常用参数 一、JVM Optimization 1、G1 G1官网说明&#xff1a;Gar…...

Java项目学生管理系统一前后端环境搭建

在现代的软件开发中&#xff0c;学生管理系统是一个常见的应用场景。通过学生管理系统&#xff0c;学校能够方便地管理学生的信息、课程安排和成绩等数据。本文将介绍如何使用Java语言搭建一个学生管理系统的前后端环境&#xff0c;并提供一个简单的示例。 1.环境搭建 学生管…...

LeetCode:169.多数元素(哈希表)

题目 第一版 思路 直接开个哈希表&#xff0c;存储每个数组中的数字和对应出现的次数。然后排序后找出对应最大value值的key。 代码 class Solution {public int majorityElement(int[] nums) {Map<Integer,Integer>map new HashMap<Integer,Integer>();for(…...

Linux指令学习

目录 1.ls指令 2.pwd命令 3.cd 指令 4. touch指令 5.mkdir指令 6.rmdir指令 && rm 指令 7.man指令 8.cp指令 9.mv指令 10.cat指令 11.more指令 12.less指令 13.head指令 14.find指令&#xff1a; -name 15.grep指令 16.zip/unzip指令&#xff1a; 17.tar…...

vue2+datav可视化数据大屏(1)

开始 &#x1f4d3; 最近打算出一个前端可视化数据大屏的系列专栏&#xff0c;这次将很全面的教大家设计可视化大屏&#xff0c;从开始到打包结束&#xff0c;其中&#xff0c;包括如何设计框架&#xff0c;如何封装axios&#xff0c;等等&#xff0c;本次使用的数据均为mock数…...

Linux 多进程并发设计-进程对核的亲缘设置

1设计结构 2 设计优点 1 充分利用多核系统的并发处理能力2 负载均衡3 职责明确&#xff0c;管理进程仅负责管理&#xff0c;工作进程仅负责处理业务逻辑 3 演示代码: //main.cpp #define _GNU_SOURCE #include<sys/types.h> #include<sys/wait.h> #include <…...

Javascript 函数介绍

Javascript 函数介绍 很多教程书一上来就讲解一堆语法&#xff0c;例如函数定义、函数调用什么。等读者看完了函数这一章都没搞懂什么是函数。 在讲解什么叫函数之前&#xff0c;我们先看下面一段代码&#xff1a; <!DOCTYPE html> <html xmlns"http://www.w3.…...

php 粉丝关注功能实现

实现粉丝关注功能的步骤如下&#xff1a; 创建用户表&#xff08;user&#xff09;和关注表&#xff08;follow&#xff09;&#xff1a; CREATE TABLE user (id int(11) NOT NULL AUTO_INCREMENT,username varchar(255) NOT NULL,email varchar(255) NOT NULL,password varc…...

深入浅出理解kafka ---- 万字总结

1.Kafka简介 Kafka 本质上是一个 MQ&#xff08;Message Queue&#xff09;&#xff0c;使用消息队列的优点&#xff1a; 解耦&#xff1a;允许独立的扩展或修改队列两边的处理过程。可恢复性&#xff1a;即使一个处理消息的进程挂掉&#xff0c;加入队列中的消息仍然可以在系…...

一对一聊天

服务端 package 一对一用户;import java.awt.BorderLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Vector;…...

IDEA版SSM入门到实战(Maven+MyBatis+Spring+SpringMVC) -Mybatis查询中返回值四种情况

第一章 Mybatis查询中返回值四种情况 1.1 查询单行数据返回单个对象 /*** 通过id获取员工信息*/ public Employee selectEmpById(int empId);<select id"selectEmpById" resultType"employee">SELECTid,last_name,email,salaryFROMtbl_employeeWHE…...

华为云安全组规则

初始发布cce,快被安全组搞死了。现在把自己的研究成果综合一下,在这里给自己留痕,希望对迷惑的朋友有帮助。 先搞懂安全组是个啥东东: 安全组规则 操作场景 安全组实际是网络流量访问策略,通过访问策略可以控制流量入方向规则和出方向规则,通过这些规则可以为加入安全组…...

MySQL之binlog文件过多处理方法

背景 MySQL由于大量读写&#xff0c;导致binlog文件特别的多。从而导致服务器disk空间不足问题。 先备份binlog文件 tar -zcvf mysql.tar.gz mysql/data/mysql-bin.00* 修改MySQL配置 binlog过期时间 show variables like expire_logs_days; 这里 0 表示 永不过期 如果为 n…...

力扣面试150题 | 88.合并两个有序数组

力扣面试150题 &#xff5c; 88.合并两个有序数组 题目描述解题思路代码实现复杂度分析 题目描述 88.合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...