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

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

我们在开发时经常会遇到一堆的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<>();


    @Override
    public 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);
    }

    @Override
    public 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;
        }

        @Override
        public When<S, C, R> when(Condition<S,C,R> condition) {
            this.strategy.condition(condition);
            return new WhenImpl(strategy);
        }

        @Override
        public 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;
        }

        @Override
        public 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;


        @Override
        public S strategy() {
            return this.strategy;
        }

        @Override
        public Condition<S,C,R> condition() {
            return this.condition;
        }

        @Override
        public Action<C, R> action() {
            return this.action;
        }

        @Override
        public Strategy<S, C, R> strategy(S s) {
            this.strategy = s;
            return this;
        }

        @Override
        public Strategy<S, C, R> condition(Condition<S,C,R> condition) {
            this.condition = condition;
            return this;
        }

        @Override
        public 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;
    }


    @Override
    public 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,直接执行action
            if (strategy.condition()==null) {
                return strategy.action().apply(c);
            }
            // 如果有condition,先判断是否满足condition,满足则执行action
            if (strategy.condition().isSatisfied(s,c)){
                return strategy.action().apply(c);
            }
        }
        // 未发现策略关于s的condition
        throw 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
        @NoArgsConstructor
        public 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


http://www.kler.cn/news/161571.html

相关文章:

  • Jquery easyui异步提交表单的两种方式
  • Vue练习 v-model 指令在状态和表单输入之间创建双向绑定
  • Vue3集成ThreeJS实现3D效果,threejs+Vite+Vue3+TypeScript 实战课程【一篇文章精通系列】
  • stm32f103使用hal库函数读写内部flash
  • 【分布式微服务专题】从单体到分布式(二、SpringCloud整合Nacos)
  • TR转发路由器测评—云企业网实现跨地域跨VPC的网络互通测评实战【阿里云产品测评】
  • tomcat环境搭建
  • 深入理解Dubbo-1.初识Dubbo
  • Csharp(C#)无标题栏窗体拖动代码
  • 推荐5款很牛的Paas平台编译构建工具
  • .netcore 操作aspose.words导出pdf
  • selenium 执行js后拿不到返回值的原因
  • IT基础监控方案:5台服务器和20台网络设备监控
  • UnityShader自定义cginc文件
  • Intellij idea 快速定位到文件的开头或者结尾的几种方式
  • 预测:2024年的安防监控行业将迎来怎样的变化?
  • 使用postman请求x5接口
  • C语言指针详解上
  • 【推荐系统】了解推荐系统的生态(重点:推荐算法的主要分类)
  • 【Java基础篇 | 面向对象】—— 聊聊什么是接口(上篇)
  • 智能优化算法应用:基于鹰栖息算法无线传感器网络(WSN)覆盖优化 - 附代码
  • 2.HTML进阶
  • 为什么伦敦银交易中支撑和阻力位这么重要?
  • 展开说说:Android之广播接收者
  • 连接服务器的ssh终端自动断开解放方法
  • Comparator Comparators Comparable Collections排序源码解析
  • SRC挖掘漏洞XSS
  • uni-app实现返回刷新上一页
  • 基于selenium工具刷b站播放量(请谨慎使用)
  • Spring AOP从入门到精通