策略模式终极解决方案之策略机
我们在开发时经常会遇到一堆的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信号处理及详解,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(Input Capture)输入捕获 输入捕获模式下,当通道输入引脚出现指定电平跳变时(上升沿/下降沿),当前CNT的值将被锁存到CCR中(把CNT的值读出来,写入到…...
webrtc 设置不获取鼠标 启用回声消除
数 getDisplayMedia()(属于 navigator.mediaDevices 的一部分)与 getUserMedia() 类似,用于打开显示内容(或部分内容,如窗口)。返回的 MediaStream 与使用 getUserMedia() 时相同。 显示鼠标与否 getDisplayMedia() 的约束条件与常规视频或音频输入资源的限制不同。 {…...
JVM虚拟机:如何查看JVM初始和最终的参数?
本文重点 在前面的课程中,我们学习了如何查看当前程序所处于的xx参数,本文再介绍一种如何参看JVM的xx参数? 查看JVM的所有初始化参数 方式一:java -XX:PrintFlagsInitial 方式二:java -XX:PrintFlagsInitial -versio…...
JVM Optimization Learning(五)
目录 一、JVM Optimization 1、G1 1、G1内存模型 2、基础概念 3、G1特点: 4、CMS日志分析 5、G1日志分析 2、GC参数 2.1、GC常用参数 2.2、Parallel常用参数 2.3、CMS常用参数 2.4、G1常用参数 一、JVM Optimization 1、G1 G1官网说明:Gar…...
Java项目学生管理系统一前后端环境搭建
在现代的软件开发中,学生管理系统是一个常见的应用场景。通过学生管理系统,学校能够方便地管理学生的信息、课程安排和成绩等数据。本文将介绍如何使用Java语言搭建一个学生管理系统的前后端环境,并提供一个简单的示例。 1.环境搭建 学生管…...
LeetCode:169.多数元素(哈希表)
题目 第一版 思路 直接开个哈希表,存储每个数组中的数字和对应出现的次数。然后排序后找出对应最大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指令: -name 15.grep指令 16.zip/unzip指令: 17.tar…...
vue2+datav可视化数据大屏(1)
开始 📓 最近打算出一个前端可视化数据大屏的系列专栏,这次将很全面的教大家设计可视化大屏,从开始到打包结束,其中,包括如何设计框架,如何封装axios,等等,本次使用的数据均为mock数…...
Linux 多进程并发设计-进程对核的亲缘设置
1设计结构 2 设计优点 1 充分利用多核系统的并发处理能力2 负载均衡3 职责明确,管理进程仅负责管理,工作进程仅负责处理业务逻辑 3 演示代码: //main.cpp #define _GNU_SOURCE #include<sys/types.h> #include<sys/wait.h> #include <…...
Javascript 函数介绍
Javascript 函数介绍 很多教程书一上来就讲解一堆语法,例如函数定义、函数调用什么。等读者看完了函数这一章都没搞懂什么是函数。 在讲解什么叫函数之前,我们先看下面一段代码: <!DOCTYPE html> <html xmlns"http://www.w3.…...
php 粉丝关注功能实现
实现粉丝关注功能的步骤如下: 创建用户表(user)和关注表(follow): 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(Message Queue),使用消息队列的优点: 解耦:允许独立的扩展或修改队列两边的处理过程。可恢复性:即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系…...
一对一聊天
服务端 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由于大量读写,导致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题 | 88.合并两个有序数组 题目描述解题思路代码实现复杂度分析 题目描述 88.合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
