zoukankan      html  css  js  c++  java
  • NChain 0.1 项目——但愿是根救命稻草

    本文内容

    • NChain 概述
    • NChain 架构
    • 使用 NChain 演示

    最近做个项目,有流程控制。也就是,执行一个流程,依赖该流程前面的流程……

    比如,编写一个文档后,需要提交给二领导,二领导同意了,再由大领导审核,即 创建 –> 提交 –> 审核(提交或审核后,当然可以打回给创建或提交,也就是,二领导或大领导认为文档不妥)。但有时,看什么样文档,事不大的话,二领导全权处理就行了。或是,大领导很信任、肯定二领导的能力,交代一般事情你全权处理就好了,不用向我请示。

    再比如,政府部门的审批,他们的审批流程每年都在变,因为政策变了。

    现在,假设有流程 A –> B –> C –> D –> E –> F,从 A 可以任意跳流程(这仅仅是业务“跳”了,程序不会),也就是,A –> B,或 A –> C,或 A –> F,或 B –> D 等等。

    起初,不想搞得太复杂,但写着写着发现,目前的结构耦合得太紧,更要命是代码不易控制,调试也有困难——很困惑。想来想去,觉得改进成 NChain 的方式似乎可以解决我目前的困境。

    下面是 NChain 的结构。

    NChain 概述

    Chain.NET(又称 NChain),是 "Chain Of Resposibility" (CoR) 职责链模式在 .NET 和 Mono 平台上的一个实现。

    这个库的概念来自于 Java 平台的 Jakarta's Commons Chain

    Chain.NET 解决方案把标准的职责链模式(CoR design pattern )与命令模式(Command design pattern )相结合,以方便灵活地处理命令。

    Chain.NET 库提供了适当接口,用来扩展标准的 CoR。

    Chain.NET 可以做到如下几个方面:

    • 试想,若将对业务实体(可以是接口,可以是类,一般是抽象类/基类)的处理看成命令,抽象成处理单元。命令描述自己如何处理以及能处理哪些业务实体。
    • 对一个业务实体,可以执行多个命令。也就是,将形成一条命令链,将业务实体传递给这个链,这样业务实体就会经过链中所有命令的处理。
    • 当其中一个命令执行失败后,链会从当前一个命令的前一个命令开始回退,也就是撤销之前所有命令对业务实体的处理。

    这样,如上所示,流程 A –> B –> C –> D –> E –> F,以及业务 object,是经过 A –> B,还是 B –> D,构造你的链就行。这就是自动化流程。

    NChain 架构

    接口

    Chain.NET 库里有几个基本接口,可以实现标准的 CoR 模式。如下:

    • ICommand
    • IFilter
    • IChain
    • IContext

    ICommand 接口表示执行的(考虑要完成特定的执行状态)工作单元。

    IFilter 接口通过 postProcess 方法扩展标准的 ICommand,该方法总是由 IChain 执行,当 IFilterexecute 方法执行完后执行。

    IChain 接口表示 ICommand 有序集合,需要处理特定的 IContext。它扩展标准的 ICommand 接口。

    IContext 接口表示执行对 command 可用的上下文环境(状态信息)。在同一个 IChaincommand,可以重新抛出(把内部异常再抛出来)来互相通信,或返回执行结果。

    基类
    • ChainBase 类——IChain 接口的基类实现

    该类提供基本的“链”功能。通过把 context 传递给“链”中的 command,处理特定的 context。

    该类提供 addCommandremoveCommand 方法添加新的 command 到 “链”和从“链”中删除 command。

    • ContextBase 类——IContext 接口的基类实现

    该类继承 System.Collection.Hashtable 类。提供标准的 context 功能。

    • CommandBase

    抽象的 CommandBase 类提供两个常量,用来标识命令的执行结果。

    对于“链”的 command,可以不继承该类。command 可以返回定义在该类中的常量(true/false),以标识执行状态。

    图 1 NChain 结构

    图 1 NChain 结构

    使用 NChain 演示

    下面是 NChain 单元测试 Demo 给出的一个演示。

    • TestCommandBase 基类继承 NChainCommandBase 基类。TestCommandBase 基类是单元测试中所有“命令”类和“后续处理命令”类(如 SimpleAdderCommandSimpleFilterForwardCommand 等)的基类。
    • TestFilterBase 基类继承 TestCommandBase 基类。

    直观上理解,这个演示规定了两种命令:命令和后续命令。如执行一个“命令”,却失败了,此时需要执行“后续命令”。如下 ChainBaseexecute 方法的代码。

    “命令”的基类是 TestCommandBase,“后续命令”的基类为 TestFilterBase。“后续命令”也是“命令”,所以 TestFilterBase 要继承 TestCommandBase

    public bool execute(IContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context", "Context is null.");
        }
     
        isFrozen = true;
     
        bool savedResult = false;
     
        Exception savedException = null;
     
        int i = 0;
        int n = commandsList.Count;
        for (i = 0; i < n; i++)
        {
            try
            {
                savedResult = ((ICommand)commandsList[i]).execute(context);
     
                if (savedResult)
                {
                    break;
                }
            }
            catch (Exception e)
            {
                savedException = e;
                break;
            }
        }
     
        if (i == n)
        {
            i--;
        }
     
        bool isHandled = false;
     
        bool result = false;
     
        for (int j = i; j >= 0; j--)
        {
            if (commandsList[j] is IFilter)
            {
                try
                {
                    result = ((IFilter)commandsList[j]).postProcess(context, savedException);
     
                    if (result)
                    {
                        isHandled = true;
                    }
                }
                catch (Exception e)
                {
                    // ignore exception during postprocessing
                }
            }
        }
     
        // Return the exception or result state from the last execute()
        if ((savedException != null) && !isHandled)
        {
            throw savedException;
        }
        else
        {
            return (savedResult);
        }
    }

    备注:

    若一个“链”有 n 个命令,当执行到第 i 个命令失败后(调用 chain 里第 iICommandexectue 方法),就执行从 i0,将所有 ICommand 接口转换成 IFilter 接口,并执行其 postProcess 方法。

    相当于,执行一个命令失败后,撤销该命令。

    另外,上面代码还判断了 ICommand 是否属于 IFilter。若是,才进行转换,并执行 postProcess 方法。因为,不是所有的命令有其相应的撤销命令。比如数据库,DML 操作有事务,但 DDL 没有,也不需要。再比如操作系统,执行 delete 命令若失败,当然要撤销,可执行 dir 命令要是失败,就无所谓了。

    如图 2 所示,所有“命令”,包括“添加(SimpleAdderCommand 类)”、“删除(SimpleRemoverCommand 类)”、“向前(SimpleForwardCommand 类)”、“完成(SimpleCompletedCommand 类)”、“异常(SimpleExceptionCommand 类)”都继承 TestCommandBase 基类。每个类都有 execute 方法。

    图 2 命令类的类图

    图 2 命令类的类图

    如图 3 所示,所有“后续处理命令”,包括“向前(SimpleFilterForwardCommand 类)”、“完成(SimpleFilterCompleteCommand 类)”和“异常(SimpleFilterExceptionCommand 类)”也都继承 TestCommandBase 基类。当然是在继承它们应该继承的 IFilter 接口和 TestFilterBase 基类的基础上。

    图 3 后续处理类的类图

    图 3 后续处理命令类的类图

    下载 Demo 运行 nchain 里的 RuntimeInstantiation 例子需要 Spring.Net

    下载 命令模式

    下载 职责链模式

    下载 http://www.springsource.org/download/community?project=Spring.NET

  • 相关阅读:
    Atitit 趋势管理之道 attilax著
    Atitit 循环处理的新特性 for...else...
    Atitit 2017年的技术趋势与未来的大技术趋势
    atitit 用什么样的维度看问题.docx 如何了解 看待xxx
    atitit prj mnrs 项目中的几种经理角色.docx
    Atitit IT办公场所以及度假村以及网点以及租房点建设之道 attilax总结
    Atitit 工具选型的因素与方法 attilax总结
    Atitit.团队文化建设影响组织的的一些原理 法则 定理 效应 p826.v4
    Atiitt 管理方面的误区总结 attilax总结
    Atitit 未来趋势把控的书籍 attilax总结 v3
  • 原文地址:https://www.cnblogs.com/liuning8023/p/2520374.html
Copyright © 2011-2022 走看看