• 面向谓词/规则编程(二)


    状态对象

    在面向谓词/规则编程https://blog.csdn.net/GengMingHui_5/article/details/126017267一文中,我们用OO的思想考察了流程/活动图中的菱形块,我们把它视为条件判断——谓词对象。带箭头或不带箭头的线条表示控制流的流向,表示顺序,表示转移(Transfer)这个好理解;那么流程图中的圆角矩形块的本质又是啥呢?也就是说,转移的究竟是什么?实际就是状态对象。流程图是表示程序控制流走向的这种抽象的图形表示法。即程序的本质,从状态流转的角度看就是自动机,FSM(有限状态机)。事件作为动力因,触发状态的转移;状态的转移过程,往往又伴随着被动/回调逻辑的执行。事件源既可以是FSM外部的干涉,也可能是内部自旋锁的打开使得条件判定为真。于是控制流转移到一下个矩形块(状态对象)。这就是流程执行的全部奥秘。下面,先铺垫几个问题:

    当我们说状态,我们在说啥?

    我们说状态时,我们在说啥?状态,隐含的意义就是:

    • 变量值会改变
    • 它某一刻的值是xx
      一个常量,在它的生命周期中不会变更,那不是我们要考察状态的对象。

    当我们说结构,我们在说啥?

    尽管状态,即变量值会改变,但结构,就是这个对象有什么域,这个通常是不变的。当然,动态型语言可以在运行时添加删除属性,但你知道,我们说结构时仍然指代它有什么。

    算法,谁的算法?

    我们常讲“数据结构和算法”,算法是谁的算法,算的什么?算法的范畴谁决定的,为什么会有P和NP问题?

    • 算法中计算和改变的是状态变量,算法是数据结构的算法
    • 数据结构决定了算法的范畴

    自动机何以可能?

    自动机为什么可能,这也干系到我们能够编程去抽象解决问题何以可能的问题。我认为,最重要的一个前提就是:状态毕竟有限。这也是为什么叫FSM(Finite-state Machine)有限状态机的原因。这也是我们编码所用的语言中为什么会引入异常机制的原因,对于不可预知的情况,我们可以统一抽象归为异常状态,就像填表时,备选项覆盖不全,通常会给一个“其他”一样。这个“其他”,是以上可选项的补集,然而它也是无限的,只是当异常发生我们把无限得可能状态摘要得对应为一种处理逻辑了。当然,无限状态机只是理论上的,现实中不可能出现,这里深究起来涉及图灵机/图灵完备/可计算性/停机问题/哥德尔不完备定理等一系列的数学证明。

    调度机制

    有了以上铺垫,我们继续考察文章伊始所谈及流程可以被视为状态机,流程图中矩形块可以被视为状态对象,以及“事件触发状态的转移;状态的转移过程,往往又伴随着被动/回调逻辑的执行”这一机制。我们编程活动,抛开具体业务语义不说,其实就是在编写一些控制流,我们暂且叫它调度机制吧。对于事件的发生,从程序的角度而言,只能通过提供的接口被调用或监听一些系统内部状态值的改变来感知事件的发生。因此,整个流程图,描述的其实就是在事件中各种谓词对象的真值表情况以及控制流流转,即状态的流转这一过程。我们就是在用编程语言描述这一整体的调度机制。至此,以上啰嗦这一堆,对于我们具体编程的指导意义在哪里呢?重要的结论就是:

    1. 流程图可以描述一切业务的工作流
    2. 我们可以用状态机作调度引擎将一个个“矩形块”封装成状态对象,将“菱形块”(谓词对象)和进入状态时要执行的回调逻辑一起封装成规则对象,来描述程序活动
    3. 将“程序 = 数据结构 + 算法”的原理,转变成架构上基于数据结构的状态对象组成得状态引擎和基于算法的规则对象组成的规则引擎结合使用来描述程序活动。

    规则引擎示例

    关于规则引擎得使用有很多库/框架。这里我们使用一个轻量级得easy-rule(本篇代码我用的easy-rules-core-4.1.0.jar),简单易用。来看一个简单示例,将1-50中能同时被5和7整除得数字找出。

    package designpattens.ruleengine;
    
    import org.jeasy.rules.annotation.*;
    
    
    /**
     * 能被5和7同时整除的数字
     */
    
    @Rule(name = "FiveSevenRule",description = "同时被5和7整除") //  也可以编程方式实现Rule接口,或使用RuleBuilder建造者来构建规则
    public class FiveSevenRule{
    
        // 标注这是一个条件(谓词对象)
        @Condition
        public boolean isFiveSevenRule (@Fact("number") Integer number) {
            return number % 5 == 0 && number % 7 == 0;
        }
    
        // 满足条件时执行这个动作
        @Action(order = 1)
        public void action1(@Fact("number") Integer number) {
    
            System.out.println("找到能被5和7同时整除的数字=====>"+number);
        }
    
        // 满足条件时执行动作二
        @Action(order = 2)
        public void action2(@Fact("number") Integer number) {
            System.out.print("动作二");
        }
    
        // 在规则链中的优先级,值越低优先级越高
        @Priority
        public int getPriority() {
            return 1;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    package designpattens.ruleengine;
    
    import org.jeasy.rules.api.Facts;
    import org.jeasy.rules.api.Rules;
    import org.jeasy.rules.api.RulesEngineListener;
    
    /**
     * 规则引擎监听器
     */
    public class MyRuleEngineListener implements RulesEngineListener {
    
        /**
         * 在执行规则集之前触发
         * @param rules 要触发的规则集
         * @param facts 触发规则前的事实
         */
        public void beforeEvaluate(Rules rules, Facts facts) {
            System.out.println("规则引擎beforeEvaluate=================================");
        }
    
        /**
         * 在执行规则集之后触发
         * @param rules 要触发的规则集
         * @param facts 触发规则前的事实
         */
        public void afterExecute(Rules rules, Facts facts) {
            System.out.println("规则引擎afterEvaluate=================================");
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    package designpattens.ruleengine;
    
    import org.jeasy.rules.annotation.*;
    
    import java.util.function.Predicate;
    
    /**
     * 互斥规则
     * 即不能被5、7同时整除
     */
    @Rule(name = "NonFiveSevenRule",description = "非同时被5和7整除")
    public class NonFiveSevenRule {
    
        @Condition
        public boolean nonFiveSevenRule (@Fact("number") Integer number) {
            Predicate<Integer> predicate = num-> num % 5 != 0 || num % 7 !=0;
            return predicate.test(number);
        }
    
        @Action
        public void printInput(@Fact("number") Integer number) {
            System.out.println( "不能同时被5和7整除数字=====>" + number);
        }
    
        @Priority
        public int getPriority() {
            return 2;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    package designpattens.ruleengine;
    
    import org.jeasy.rules.annotation.*;
    
    /**
     * 普通数字规则
     * @author gmh
     * 2022/5/5 10:30
     */
    @Rule(name = "NormalNumRule",description = "普通数字处理规则")
    public class NormalNumRule {
    
        @Condition
        public boolean nonFiveSevenRule (@Fact("number") Integer number) {
            return true;
        }
    
        @Action
        public void printInput(@Fact("number") Integer number) {
            System.out.println( "普通数字=====>" + number);
        }
    
        @Priority
        public int getPriority() {
            return 3;
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    package designpattens.ruleengine;
    
    import org.jeasy.rules.api.*;
    import org.jeasy.rules.core.DefaultRulesEngine;
    
    /**
     * 创建规则引擎
     */
    public class RuleEngine {
    
    /*
        // 面向过程的写法
        public void fizzbuzz() {
            for(int i = 1; i <= 50; i++) {
                if (((i % 5) == 0) && ((i % 7) == 0)){
                    System.out.print("target number:"+i);
                }else {
                    System.out.print("normal number:"+i);
                }
            }
        }
    */
    
    
        public static void main(String[] args) {
            // 创建规则引擎,设置规则参数策略
            /*
            rulePriorityThreshold:当优先级超过指定的阈值时,跳过余下的规则。
            skipOnFirstAppliedRule:当一个规则成功应用时,跳过余下的规则。
            skipOnFirstFailedRule:当一个规则应用失败时,跳过余下的规则。
            skipOnFirstNonTriggeredRule:当一个规则未触发时,跳过余下的规则
             */
            RulesEngineParameters rulesEngineParameters = new RulesEngineParameters().skipOnFirstAppliedRule(false);
            DefaultRulesEngine rulesEngine = new DefaultRulesEngine(rulesEngineParameters);
    
            // 注册规则监听器和规则引擎监听器
            rulesEngine.registerRulesEngineListener(new MyRuleEngineListener());
            RuleListener myRuleListener = new RuleListener() {
                @Override
                public void onSuccess(Rule rule, Facts facts) {
                    System.out.println("规则执行成功回调!!!");
                }
            };
            rulesEngine.registerRuleListener(myRuleListener);
    
            // 创建规则链
            Rules rules = new Rules();
            rules.register(new FiveSevenRule());
            rules.register(new NonFiveSevenRule());
            rules.register(new NormalNumRule());
    
    
            // 根据既定事实触发规则
            Facts facts = new Facts();
            for (int i = 1; i <= 50; i++) {
                facts.put("number", i);
                // 发射规则和事实
                rulesEngine.fire(rules, facts);
            }
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    你可能会不屑,明明写个for循环就解决得小问题,干嘛绕来绕去?其实麻雀虽小,五脏俱全。这里重点要展示的是这种抽象,玩味得是如何将我们思考问题时的一些规则进行抽象。如果你拿去运行了,你就知道,以小见大,对于复杂问题,我们可以利用规则抽象得方式,动态组装规则引擎,从而完成动态逻辑!而不再是依靠写死得if…else…代码来作控制流,每次改动逻辑都要去修改代码。

    状态机引擎+规则抽象调度示例

    这里我们以一个最简单得“登录验证到主页”得一个小流程来展示。如果录入不对,就继续录入,来实现流程图中得回向跳转和循环。

    package designpattens.state.ruleengine.stateandruleengine;
    
    /**
     * 认证流程状态
     * @author gmh
     * 2022/5/12 9:26
     */
    public interface IAuthState {
    
        String getName();
    
        void enterState();
    
        IAuthState checkTransfer();
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    package designpattens.state.ruleengine.stateandruleengine;
    
    /**
     * 表单录入状态
     * @author gmh
     * 2022/5/12 9:30
     */
    public class FormInputState implements IAuthState{
        @Override
        public String getName() {
            return "forminput";
        }
    
        @Override
        public void enterState() {
            System.out.println("进入登录页面-表单录入状态");
            FormInputRule formInputRule = new FormInputRule();
            if (formInputRule.evaluate()) {
                formInputRule.execute();
            }
        }
    
        @Override
        public IAuthState checkTransfer() {
            if(InfoContainer.contains("toAuth")){
                return new AuthenticationState();
            }
            return null;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    package designpattens.state.ruleengine.stateandruleengine;
    
    /**
     * 认证状态
     * @author gmh
     * 2022/5/12 9:32
     */ public class AuthenticationState implements IAuthState{
        @Override
        public String getName() {
            return "authentication";
        }
    
        @Override
        public void enterState() {
            System.out.println("进入认证状态");
            AuthenticationRule authenticationRule = new AuthenticationRule();
            if (authenticationRule.evaluate()) {
                authenticationRule.execute();
            }
        }
    
        @Override
        public IAuthState checkTransfer() {
            String authResult = InfoContainer.getInfo("authResult");
            if (null!=authResult && authResult.equalsIgnoreCase("true")) {
                return new HomeState();
            }else {
                return  new FormInputState();
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    package designpattens.state.ruleengine.stateandruleengine;
    
    /**
     * 主页数据加载
     * @author gmh
     * 2022/5/12 9:33
     */
    public class HomeState implements IAuthState{
        @Override
        public String getName() {
            return "home";
        }
    
        @Override
        public void enterState() {
            System.out.println("进入主页状态");
            HomeLoadRule homeLoadRule = new HomeLoadRule();
            if (homeLoadRule.evaluate()) {
                homeLoadRule.execute();
            }
        }
    
        @Override
        public IAuthState checkTransfer() {
            return new FinishState();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    package designpattens.state.ruleengine.stateandruleengine;
    
    /**
     * 终止态
     * @author gmh
     * 2022/5/12 11:04
     */
    public class FinishState implements IAuthState{
        @Override
        public String getName() {
            return "finish";
        }
    
        @Override
        public void enterState() {
            System.out.println("流程结束<<");
        }
    
        @Override
        public IAuthState checkTransfer() {
            return null;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    package designpattens.state.ruleengine.stateandruleengine;
    
    import org.jeasy.rules.annotation.Action;
    import org.jeasy.rules.annotation.Condition;
    import org.jeasy.rules.annotation.Priority;
    import org.jeasy.rules.annotation.Rule;
    
    import java.util.Random;
    
    /**
     * 表单录入规则
     * @author gmh
     * 2022/5/12 9:34
     */
    @Rule(name = "forminput",description = "表单录入规则")
    public class FormInputRule {
    
    
        @Condition
        public boolean evaluate(){
            return true;
        }
    
    
        @Action
        public void execute(){
            // 录入表单
    
            System.out.println("正在输入登录信息...");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Random random=new Random();
            int i = random.nextInt(10);
            if(i%2==1){
                InfoContainer.addInfo("toAuth","admin:123456");
            }else {
                InfoContainer.addInfo("toAuth","admin:111111");
            }
            System.out.println("输入信息:"+InfoContainer.getInfo("toAuth"));
        }
    
        @Priority
        public int getPriority(){
            return 0;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    package designpattens.state.ruleengine.stateandruleengine;
    
    import org.jeasy.rules.annotation.Action;
    import org.jeasy.rules.annotation.Condition;
    import org.jeasy.rules.annotation.Priority;
    import org.jeasy.rules.annotation.Rule;
    
    /**
     * 认证规则
     * @author gmh
     * 2022/5/12 9:56
     */
    @Rule(name = "Authentication",description = "认证提交")
    public class AuthenticationRule {
    
        @Condition
        public boolean evaluate(){
            return InfoContainer.contains("toAuth");
        }
    
        @Action
        public void execute(){
            final String toAuth = InfoContainer.getInfo("toAuth");
            final String[] split = toAuth.split(":");
            if(split[0].equals("admin")&&split[1].equals("111111")){
                InfoContainer.addInfo("authResult","true");
                System.out.println("认证成功");
            }else {
                InfoContainer.addInfo("authResult","failed");
                System.out.println("认证失败");
            }
    
        }
    
        @Priority
        public int getPriority(){
            return 1;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    package designpattens.state.ruleengine.stateandruleengine;
    
    import org.jeasy.rules.annotation.Action;
    import org.jeasy.rules.annotation.Condition;
    import org.jeasy.rules.annotation.Rule;
    
    /**
     * 主页数据加载规则
     * @author gmh
     * 2022/5/12 10:05
     */
    @Rule(name = "home",description = "进入主页加载数据")
    public class HomeLoadRule {
    
        @Condition
        public boolean evaluate(){
            String authResult = InfoContainer.remove("authResult");
            return null!= authResult && authResult.equalsIgnoreCase("true");
        }
    
    
        @Action
        public void execute(){
            InfoContainer.addInfo("home","currUser:admin");
            System.out.println("主页数据:"+InfoContainer.getInfo("home"));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    package designpattens.state.ruleengine.stateandruleengine;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 信息容器
     * @author gmh
     * 2022/5/12 9:36
     */
    public class InfoContainer {
    
        private static final Map<String,String> infoCtn = new HashMap<>();
    
        public static String getInfo(String key){
            return infoCtn.get(key);
        }
    
        public static void addInfo(String key,String value){
            infoCtn.put(key,value);
        }
    
    
        public static boolean contains(String key){
            return infoCtn.containsKey(key);
        }
    
        public static String remove(String key){
            return infoCtn.remove(key);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    package designpattens.state.ruleengine.stateandruleengine;
    
    /**
     * 使用状态机+规则引擎进行业务调度
     * @author gmh
     * 2022/5/12 9:28
     */
    public class AuthBiz  implements Runnable{
    
        private IAuthState currState;
    
        public AuthBiz(IAuthState currState) {
            this.currState = currState;
        }
    
        public AuthBiz setCurrState(IAuthState currState) {
            this.currState = currState;
            return this;
        }
    
        @Override
        public void run() {
            currState.enterState();
            while (!currState.getName().equalsIgnoreCase("home")) {
                IAuthState nState = currState.checkTransfer();
                if (null != nState && !nState.getName().equalsIgnoreCase(currState.getName())) {
                    this.setCurrState(nState);
                    currState.enterState();
                }
            }
        }
    
        public static void main(String[] args) {
            IAuthState initState = new FormInputState();
            Thread thread = new Thread(new AuthBiz(initState));
            thread.start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    模拟的可能有些粗糙,请忽略细节看思想。值得注意的是,这里我把状态划分为表单录入,认证,进入主页(认证成功)几种。其实使用状态模式编程不在于你怎样划分状态,重点在于状态之间的流转能闭环自洽,来完成你的业务。再就是,状态对象,既然叫状态对象,每个状态对象都是应该有自己的状态的。而这里我用了享元模式,将各个状态对象应该持有维护的状态数据和并在一起,放入叫做InfoContainer的信息容器对象作为一个大而全的状态对象了;而这也体现了一个深刻的含义,在一项领域业务活动中,所有的状态数据全集,就描述了这个领域的全部。我们五花八门的写法,不过是分还是合的问题。那么推而广之,如果把围绕各个状态的操作也集中到一个对象身上,始得每个对象需要执行各自业务时都去与它通讯,由它统一调度派发,那是什么模式?——中介者模式。

    总结

    1. 可以使用状态机+规则引擎进行业务调度
    2. 一套流程图,本质上是各个规则得判断执行和状态数据得转移
    3. 规则引擎本质是责任链,适合线性迭代执行;而在一套流程图中不只有线性得、结构化 得流转,经常有任意得goto(jump)包括向前跨越或回跳、反身循环等,这本质上是状态得自由跳转, 此时不适用规则链。但这并不妨碍从规则的角度对流程图进行整体抽象,每一步condition+action都是一个规则,因此,使用状态机作为总调度引擎与对规则进行抽象之间并不矛盾。
    4. 在每个状态中,可以零散得执行规则,也可以将规则进行组装链,由规则引擎进行局部调度。
  • 相关阅读:
    敏捷开发中,Sprint回顾会的目的
    【设计模式之模板方法模式 -- C++】
    for、while、do While、for in、forEach、map、reduce、every、some、filter的使用
    【VictoriaMetrics的vmbackupmanager】这个一年卖 2 万美元的功能,我做出来了
    [机器学习] 监督学习和无监督学习
    Windows10实用的12个快捷组合键
    python基础语法(JSON、类、对象)
    Mac 安装软件各种报错解决方案
    如何实现矩阵的重采样问题
    Greenplum数据库故障分析——版本升级后gpstart -a为何返回失败
  • 原文地址:https://blog.csdn.net/GengMingHui_5/article/details/126153706