这是我目前正在进行的工作,记录下来顺便理理思路
背景:
我于今年入职这家公司,由于历史等原因,公司内部软件系统处于没有软件架构的状态,同时待开发的功能较多,其中工作流审批部分使用的引擎是一个叫Captaris的完全找不到任何资料,且其开发者疑似倒闭,使用它的原因是因为集团在使用,而开发时没有设计人员,所以程序员没细想就用了,同时由于没有任何资料,这个工作流引擎用的面目全非没有给开发带来任何好处,并且无法完成有些特殊需求。
针对这种情况,当时决定将这种开发方式废弃,短时间内封装一个可以完成支持当时审批需求的单据流转功能,当时用了5天(非常简陋),但至少开发效率提高了不止一倍;但是,原本运行着的流程要一点一点的平稳移动过来,同时有些技术以外的原因,原来的个别流程不会移植,面对这种情况,我采用了依赖注入的方式,把原来的工作流封装了下和我新做的这个借助配置文件在不同的流程采取不同的注入模块,让流程外部完全不关心流程内部的实现情况,方面以后会遇到的各种变动。
下面进入正题:
来了不能拒绝的需求,1.审批后要发邮件,可以通过邮件进行审批;2.审批同时要把下一步的审批人列出来(这个要特殊说一下,我的审批流,下一步的审批人是不确定的,根据配置和当前业务数据条件来决定下一步审批人)等等;
实现这类需求,我有两种选择:一是在流程内部实现,但是这样会导致业务与流转混杂,流程流转相关业务与流转的是一定要分离,而且这种业务在我的公司变化的情况很多,开闭原则就不多说了;二是在流程外部实现,当然第一种PASS了我只能选这个了。
在流程外部实现,面临的问题是:1.依赖注入了流程实现,所以流程过程中的信息完全获取不到;2.两种流转机制差异极大,难以统一,无法统一返回信息的结构。
第一个问题的解决办法,既然外部取不到,理所当然会想到,将外部需要流传过程信息的方法传给工作流的实现模块,由工作流去执行,比如在审批结束时的后置事件:
//定义一个委托 public delegate void ExecutionEndEventHandler //在工作流实现部分提供外部一个注册的方法 public override void RegisterExecutionEndEvent(Delegate executionEnd, string userID) { if (executionEnd != null && DoRoleValidate(userID)) { process.RegisterExecutionEndEvent(executionEnd); } } public void RegisterExecutionEndEvent(Delegate executionEnd) { exec.ExecutionEnd += (WorkFlowEvent.ExecutionEndEventHandler)executionEnd; } //当外部需要时,只需要将事件注册进来即可 WorkFlowFactory.RegisterExecutionEndEvent(new WorkFlowEvent.ExecutionEndEventHandler(OnExecutionCompleted), "userID ");
第二个问题,费了些脑筋,最开始用了嵌套hashtable的方式实现的,但是始终感觉不舒服,看着就各种不舒服,最后终于在群里朋友深蓝医生的提醒下,想起微软还有个.Data的命名空间,有个东西叫DataSet,它可以返回任意的结构,可结构的信息,这个…,着实太久不用下意识的就忘记了。
public void OnExecutionCompleted(DataSet process) { DataTable work = process.Tables["work"]; }
至此,大体思路就确定下来了,剩下的比如注册事件的权限,比如可以返回的信息控制等等,都是细节,我去鼓捣了,再见!