“思考得少,瞎干得多”,就是目前企业开发的现状。瞎干了两个月后,回头来分析一下一个有趣的流程,是我们目前项目中最复杂的一个流程(因为要完成它而不能动脑,所以复杂)。

首先把UML书上的案例扔到一边,那个是齐全的菜谱、佐料、原料而真实项目是荒地。想想走到荒地上给自己整一顿满汉全席,不容易啊……

现在已经忘了最初听到这个流程的描述是怎么样的了。大概就是“一个待办项会发送和接收很多次,也可以发送接收一次,发送完后就不能再次发送了,最后一个接收结束后才能结束整个流程”——够昏的吧^O^遇到这种事千万不能听客户、需求人员甚至项目经理的,架构师才是设计这个系统的人,不能自己分析、定义业务对象,下课去吧。

第一反应就是发送和接收必须是两个不同的待办项,随后是必须定义两个不同的动作:完全发送和部分发送。概念一定要区分准确。

随后关于如何叫完全发送和部分发送有几次需求上的变化,但不影响流程的执行规则。这个就形成了我在业务流程配置一文中写的ResponseTask类,当时的需求就是请求-接收,所以只写了两个Task;随后扩展成了每接收之后还有一个任务叫填写意见书,所有的意见书完成之后再开始一个新的任务。所以就改成了:请求-接收-响应三个操作,修改ResponseTask,增加了ResponseType这一枚举值属性,修改了结束的算法。目前的流程执行规则是相当死板的,完全硬编码在引擎内部,无法改变。以下是ResponseTask类和执行代码:

using System;
using System.Collections.Generic;
using System.Xml.Serialization; 

namespace Microsoft.Applications.ChinaMobilePMS.FlowEngine
{
    public class ResponseTask : TaskBase, IComparable<ResponseTask>
    {
        private int requestNumber = 0;
        private ResponseType responseMode = ResponseType.Request; 

        [XmlAttribute("RequestNumber")]
        public int RequestNumber
        {
            get { return requestNumber; }
            set { requestNumber = value; }
        } 

        [XmlAttribute("Mode")]
        public ResponseType ResponseMode
        {
            get { return responseMode; }
            set { responseMode = value; }
        } 

        #region IComparable<ResponseTask> Members 

        public int CompareTo(ResponseTask other)
        {
            if (this.responseMode < other.responseMode) { return -1; }
            else if (this.responseMode == other.responseMode) { return 0; }
            else { return 1; }
        } 

        #endregion
    }
} 


using System;
using System.Collections.Generic;
using System.Xml.Serialization; 

namespace Microsoft.Applications.ChinaMobilePMS.FlowEngine
{
    public class Activity : IActivity
    {
        //...
        public void StartActivity(string actionValue)
        {
            switch (mode)
            {
                case TaskMode.Response:
                {
                    responseTasks.Sort();
                    ResponseTask requestTask = responseTasks[0];
                    ResponseTask receiveTask = responseTasks[1];
                    ResponseTask responseTask = responseTasks[2];
                    if (status == StatusType.Scheduled)
                    {
                        status = StatusType.InProgress;
                        requestTask = responseTasks[0];
                        requestTask.CreateTask();
                    }
                    else if (status == StatusType.InProgress)
                    {
                        switch (actionValue)
                        {
                            case "CompleteSubmit":
                                requestTask.Approve += new ApproveHandler(receiveTask.CreateTask);
                                requestTask.ApproveTask();
                                receiveTask.RequestNumber++;
                                break;
                            case "Submit":
                                receiveTask.CreateTask();
                                receiveTask.RequestNumber++;
                                break;
                            case "Receive":
                                receiveTask.Approve += new ApproveHandler(responseTask.CreateTask);
                                receiveTask.ApproveTask();
                                receiveTask.RequestNumber--;
                                responseTask.RequestNumber++;
                                break;
                            case "Reject":
                                receiveTask.Reject += new RejectHandler(requestTask.CreateTask);
                                receiveTask.RejectTask();
                                receiveTask.RequestNumber--;
                                break;
                            case "Response":
                                responseTask.ApproveTask();
                                responseTask.RequestNumber--; 
                                if (((requestTask.Status == StatusType.Completed) && (receiveTask.RequestNumber <= 0) && (responseTask.RequestNumber <= 0)))
                                {
                                    CompleteActivity();
                                }
                                else
                                {
                                    responseTask.Status = StatusType.InProgress;
                                }
                                break;
                            default:
                                break;
                       }
                    }
                }
               break;
            }
        }
    }
} 


昨天参考了Workflow Pattern,其实这个被我表达为Request-Receive-Response的流程的标准描述是以下两个的综合:

Parallel split pattern


Synchronization pattern


于是我拿出纸和笔,画下了这幅图:


想了想,这副图没有把完全发送与部分发送的分支表达出来,于是改成了这幅:


现在呢,有了选择。如果用户选择部分发送,它将走图一的流程,否则就一个简单的2-3-4走完。但是,这时依然缺少了东西,缺少了4开始的条件。并且,部分提交和完全提交唯一的区别就是是否结束1,所以不用专门配分支,再把选择和任务2视为并发任务,因为他们没有先后关系,虽然界面上操作有先有后,但这个选择不能决定任务2是否产生。又改:


这一个算是比较满意的分析模型。根据这个模型,先前硬编码的执行算法将被抽象为ControlRule,它将继承自RuleBase,代表了上图的流程线。而这个分支是用户在执行时选择的,暂定名为Choice:
<ControlRule Mode="Choice">
    <Choice Result="Complete">
        <Then />
    </Choice>
    <Choice Result="Partial">
        <Then />
    </Choice>
</ControlRule> 


规则引擎将解释这个配置并执行。而在Task的执行上,也会定义在配置中,而不是现在这样硬编码。例,选择完全提交之后结束任务一:
<ControlRule Mode="Choice">
    <Choice Result="Complete">
        <Then>
            <Task ID="1" Action="End" Mode="auto" />
        </Then>
    </Choice>
</ControlRule>


这里Mode="auto"意为系统自动处理,不需要产生待办项。接下来是关于任务2的产生,它与Choice并行关系的,而且是任务一提交后必然无条件产生的,故命名为Unconditional:
<ControlRule Mode="Choice" />
<ControlRule Mode="Unconditional">
    <Task ID="2" Action="Start" Mode="manual" />
</ControlRule> 


这里的Mode="manual"表示会生成一条待办项,到达指定办理人处。对于最后任务4启动的验证:
<ControlRule Mode="Conditional">
    <Condition>
        <Task ID="1" Status="Completed" />
        <Task ID="2" Status="Completed" />
        <Task ID="3" Status="Completed" />
    </Condition>
    <Then>
        <Task ID="4" Action="Start" Mode="manual" />
    </Then>
</ControlRule> 


至此,已经基于规则实现了这个流程,其中的三条规则是:选择型、条件型、无条件型;进一步了解之后再进行补充。下一次,将围绕任务进行面向行为的分析,核心问题还是办理人的持久化目的地。
评论
发表评论

您还没有登录,请登录后发表评论

RCFans
搜索本博客
博客分类
最近加入圈子
最新评论