策略模式终极解决方案之策略机
我们在开发时经常会遇到一堆的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 中的元素数目。 请你 合并…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...