工作流内部工作原理(一)

读过了Essential Windows Workflow Foundation这本书后,我觉得有必要为WF4也写一课。其实,WF4的工作原理和它的前一个版本几乎一模一样,但是它们的编程模型却是很不一样。我们会从可序列化的委托(Serializable Delegate)开始,慢慢深入去看WF4的设计。

首先我们先看一下CLR里对Continuation的支持吧。Continuation是一个程序执行中一个可以保存的时间点,所以它必须保存一个对执行代码的指针,而delegate就是一种这样的指针。Delegate最棒的地方就是它可以被序列化,反序列化,然后继续执行。我们可以看一下以下的代码:

代碼示例: SerializableDelegate

可序列化delegate给了我们一个方法去暂停一个线程,然后让它在另外一个进程中继续,这个进程甚至可以是在另外一台电脑上。这样做的好处很多,而最重要的就是我们除掉了所有的「亲和度」,代码再不依赖于进程,甚至不依赖于电脑。这样的话我们就可以很好的扩展我们的系统,只需要多买电脑,也任务分派到不同的机器就可以,关键是代码可以随时停下来。同时,我们有了控制。我们可以把序列化了的delegate删掉,这样就可以取消了这个进程。工作可以暂停很长的时间,而不用担心系统会佔用了内存资源。接下来我们看一下以下的代码示例,看看我们如何使用可序列化delegate把一个程序拆成不同的进程:

代碼示例: Version 1

执行这程序三遍,你会发现在控制台上会显示出“Hello world to homemade workflow foundation!”。在以上的代码,我们就简单的创建了一个简单的工作流程序了。不用说,这个范例有很多问题,我们有很多可以改善它的地方。第一步我们就先把对可扩展性的支持和业务逻辑分离出来。我们会提炼一个名为ReadReadWrite的类,然后把业务逻辑集中在它上面,这样我们就写了Version 2

1-to-2

代碼示例: Version 2

首先,留意我在主程序中写了一个while循环,这个只是一个方便的捷径而已。对于我们来说,知道这些程序能够分开就好,实在没有必要真的分开执行。这次的重构其实很简单直接,不过有一点值的留意的就是我把NextDelegate变成一个ReadReadWrite的一个成员。这样做的原因是为了让每一个delegate都有一样的signature.

到了这个时候,主程序和业务逻辑已经是分离了。我们还是有一些耦合点,例如主程序需要知道程序的起点是RunStep1,而储存接续点的成员是NextDelegate,这样我们的主程序就不能是一个普遍而适用于任何程序的主程序。去掉这些耦合的方法说也简单,就是定义一个父类,让主程序与父类耦合而不会和业务逻辑耦合,这个父类我们命名成Activity.

2-to-3

代碼示例: Version 3

这次的重构也是非常的简单。读一下ReadReadWrite的代码,这样的代码已经不难写。其中有一点我们不喜欢的地方就是Execute和RunStep2里面做的事情几乎一模一样,从代码的角度去看最好我们可以重用。我们试着提炼,然后发现两个问题。一个是它们是在更新不同的状态变量,而另外一个是它们返回不同的delegate。它们返回不同delegate的这问题尤其严重,因为读文件和程序执行顺序是两件垂直的事情。我们把程序控制和实际工作混合在一起会破坏了代码的内聚性。接下来我们试着把它们区分出来。

3-to-4

代碼示例: Version 4

Sequence activity 的实现一点也不简单,而且它也不是最优化的。下一篇我们会讨如何优化Sequence。现在我们先专注于除掉Read1和Read2之间的重覆。到这里Read1和Read2都是在读文件了,所以我们可以通过名字去找状态变量,这样就可以完全的把重覆除掉了。

4-to-5

代碼示例: Version 5

走到这里,我们已经可以写能重用的Activity,而且这些Activity都不用管有关序列化的细节。不去读Main的代码,我们甚至不知道序列化有实际进行。看看Read和Write,是不是开始有点像WF4里Activity的API呢?下一篇,我们会继续这个例子,去探讨为甚麽Activity.Execute会有一个参数,和这个参数如何把程序兴资料区分出来。

HomeMadeWF.zip