首先再次说明一下我的想法:
根据 [1]几天狂想的成果:工作流的定义与模型 对工作流的描述:
一、 下面给出了几个核心类型定义:
需要说明的是Action.Do()方法,它的实现者根据Param决定怎么执行一个动作,并返回一个结果。而Action的继承者Step的Do()方法,它除了根据Param,还要等待Waits中所有Step的结果,当它返回结果前,会适时引发StepTo事件以通知它的调用者下一步可以进行哪些Step的执行。实现以上接口,已经可以做工作流的开发了,一些取决于Do方法的实现。而IResult和IParam则是为了让Action能处理所有的类型。
举个例子说明IAction的灵活性:
public partial class ActionForm : Form , JCLib.WorkFlow.IAction
{
Result _Result = null;
public JCLib.WorkFlow.IResult Result{get{return _Result as JCLib.WorkFlow.IResult;}}
Param _Param = null;
public JCLib.WorkFlow.IParam Param { get { return _Param; } set { _Param = value as Param; } }
public JCLib.WorkFlow.IResult Do()
{
this.ShowDialog();
return _Result as JCLib.WorkFlow.IResult;
}
}
那么在这个窗体运行期间,可以做任意的事情,直到生成合适的Result,在关闭窗体后,结果也随之返回给调用者。调用者根据结果去判断应该做哪些后续的事情,对于Step也是一样道理,不同的是Do方法可能会判断它的先决条件是否成立,否则拒绝运行该窗体并返回一个空结果。
二、 为了方便,写了一些抽象类实现了接口中一些通用的操作,以减少实现者的代码量。
这些抽象类没有什么特别的地方。
要注意的是Activator,它是一个工具类,且具有一系列的静态方法如Do,它可以根据传入的参数利用反射去执行一个Action或Step。这是令人激动一个亮点:可以动态加载指定的程序集并有选择地去执行里边的步骤或方法!
看一下下面的代码:
它将一个动态执行一个Action,并将结果显示出来。
ActionTest是当前的窗体,而 ActionForm也恰巧在当前运行的程序集里 。如果目标类型不当前程序集中,则可以通过动态加载程序集的方法来加载。
- 一个工作流是一串步骤的组合,每个步骤都可以看成是一个状态,状态的转移相当于流程的分支控制;状态内部实际上也是一个工作流,是整个工作流的一个子流;同时定义了依赖集Waits,允许该步骤等待前面几个工作的特定结果;定义了转向集Branches,表示该步骤取得某一结果,工作流中某些步骤可以开始执行。
- 工作流中的每一个步骤都可以将步骤持久化或反持久化,可以进行权限控制。这是要逐步实现的功能。
根据 [1]几天狂想的成果:工作流的定义与模型 对工作流的描述:
WorkFlow :<&Step>
Step : <Steps , Branches , Waits>
Branch:<Result , Steps>
Wait:<Step,Result>
为了便于实现,进一步抽象出 Action作为一个动作,它执行一个动作并返回一个结果。一个步骤也是一个动作,但在动作的基础上多了前提条件等待和分支控制限制。Step : <Steps , Branches , Waits>
Branch:<Result , Steps>
Wait:<Step,Result>
一、 下面给出了几个核心类型定义:
1.动作状态、参数和结果的定义
2.分支定义
3. 动作和步骤的定义
![动作状态、参数和结果](https://p-blog.csdn.net/images/p_blog_csdn_net/gwl1984/ActionState_IResult_IParam.jpg)
2.分支定义
![分支的定义](https://p-blog.csdn.net/images/p_blog_csdn_net/gwl1984/Branch.jpg)
3. 动作和步骤的定义
![动作和步骤的定义](https://p-blog.csdn.net/images/p_blog_csdn_net/gwl1984/IAction_IStep.jpg)
需要说明的是Action.Do()方法,它的实现者根据Param决定怎么执行一个动作,并返回一个结果。而Action的继承者Step的Do()方法,它除了根据Param,还要等待Waits中所有Step的结果,当它返回结果前,会适时引发StepTo事件以通知它的调用者下一步可以进行哪些Step的执行。实现以上接口,已经可以做工作流的开发了,一些取决于Do方法的实现。而IResult和IParam则是为了让Action能处理所有的类型。
举个例子说明IAction的灵活性:
public partial class ActionForm : Form , JCLib.WorkFlow.IAction
{
Result _Result = null;
public JCLib.WorkFlow.IResult Result{get{return _Result as JCLib.WorkFlow.IResult;}}
Param _Param = null;
public JCLib.WorkFlow.IParam Param { get { return _Param; } set { _Param = value as Param; } }
public JCLib.WorkFlow.IResult Do()
{
this.ShowDialog();
return _Result as JCLib.WorkFlow.IResult;
}
}
那么在这个窗体运行期间,可以做任意的事情,直到生成合适的Result,在关闭窗体后,结果也随之返回给调用者。调用者根据结果去判断应该做哪些后续的事情,对于Step也是一样道理,不同的是Do方法可能会判断它的先决条件是否成立,否则拒绝运行该窗体并返回一个空结果。
二、 为了方便,写了一些抽象类实现了接口中一些通用的操作,以减少实现者的代码量。
1.动作和步骤
2.参数和结果
3.一个工具:Activator
![动作和步骤](https://p-blog.csdn.net/images/p_blog_csdn_net/gwl1984/Action_Step.jpg)
2.参数和结果
![参数和结果](https://p-blog.csdn.net/images/p_blog_csdn_net/gwl1984/Param_Result.jpg)
3.一个工具:Activator
![一个工具:Activator](https://p-blog.csdn.net/images/p_blog_csdn_net/gwl1984/Activator.jpg)
这些抽象类没有什么特别的地方。
要注意的是Activator,它是一个工具类,且具有一系列的静态方法如Do,它可以根据传入的参数利用反射去执行一个Action或Step。这是令人激动一个亮点:可以动态加载指定的程序集并有选择地去执行里边的步骤或方法!
看一下下面的代码:
JCLib.WorkFlow.IResult result = JCLib.WorkFlow.Action.Do(typeof(ActionTest).Assembly, "JCLibTester.ActionForm");
MessageBox.Show(result.ResultCode + " " + result.ResultInfo);
MessageBox.Show(result.ResultCode + " " + result.ResultInfo);
它将一个动态执行一个Action,并将结果显示出来。
ActionTest是当前的窗体,而 ActionForm也恰巧在当前运行的程序集里 。如果目标类型不当前程序集中,则可以通过动态加载程序集的方法来加载。