我们为什么需要WF
本文是[我们为什么需要工作流]的姊妹篇,我使了类似的文风,
我们为什么需要WF
以前有人对我说,WF很难用,明明很简单的一个功能,用WF去做却那么繁琐,
有这种想法,那我觉得有两种可能,
一,你要实现的这个功能确实太简单
二,你把这个功能的实现过程想的太简单
先看一组列子
这是一组非常简单的例子,分别是四个主题,分别代表程序发展的四个阶段
- 什么是程序
- 什么是具有控制流语句程序的控制流语句
- 什么是交互程序
- 什么是可视化交互程序
程序
程序是一连串指令的集合,
下面是一个技术算法的程序,
记得在89年的时候,我上小学5年级,那时我在PC1500上第一次用Basic写出了具有这个功能的程序.
那时候,每要做一次计算都要把程序再敲一遍,在我眼里,PC1500这个大家活还不如一个计算器
这是我那个Basic功能的C#版
class Program { static void Main(string[] args) { int x = 1; //加数 int y = 2; //被加数 int z = x + y; // 相加 System.Console.WriteLine(z); //在屏幕打印结果 } } |
具有控制流语句程序的控制流语句
控制流语句,
不久,我学会了一个很有意思的指今,他可以根据我设定的条件执行不同的代码,这时,我觉得PC1500这个大家活还有点意思.
这是我那个Basic功能的C#版
class Program { static void Main(string[] args) { string input = "123"; double temp ; bool b=double.TryParse(input,out temp);
if (b) { System.Console.WriteLine("你输入的数字是:{0}",temp); } else { System.Console.WriteLine("你输入的不是数字"); } }
} |
交互程序
交互程序,有用户参与的,用户可以在程序的预设点控制程序的执行
初中三年,由于家人认为"玩"电脑是不务正业,会耽误学习,到了高中,胆大了,又开始"完"电脑了,这时用的是386,
我学会了一门新语言FoxBase,他很神奇,可以等我输入点什么以后再继续执行
这是我那个FoxBase功能的C#版
class Program { static void Main(string[] args) { while (true) { System.Console.WriteLine("要查看系统日期请按[y],按其它键退出程序"); string input = System.Console.ReadLine(); if (input == "y") { System.Console.WriteLine(DateTime.Now); } else { return; } } } } |
可视化程序
可视化程序
到了大学,虽然我学的是文科,但我对编程的热情依然没改,一次,我无意中接处到了VB,这是一个让我疯狂的语言,他竟然可以写出Windows中的窗口.
这是我那个VB功能的C#版
//数据模型 public class myData { public int x; public int y; } |
//数据操作 public static class myMaths { public static int add(myData data) { int z = data.x + data.y; return z; } } |
//展现1 public class windows1 : System.Windows.Forms.Form { System.Windows.Forms.Label title_label = new System.Windows.Forms.Label() { Text="请输入x"}; System.Windows.Forms.TextBox x_textBox = new System.Windows.Forms.TextBox() { Top = 30 }; System.Windows.Forms.Button ok_button = new System.Windows.Forms.Button() { Text = "确定",Top = 30, Left = 200}; public string x; public windows1() { this.Controls.Add(title_label); this.Controls.Add(x_textBox); this.Controls.Add(ok_button); ok_button.Click += new EventHandler(ok_button_Click); } void ok_button_Click(object sender, EventArgs e) { x = x_textBox.Text; this.Hide(); } } |
//展现2 public class windows2 : System.Windows.Forms.Form { System.Windows.Forms.Label title_label = new System.Windows.Forms.Label() { Text = "请输入y" }; System.Windows.Forms.TextBox y_textBox = new System.Windows.Forms.TextBox() { Top = 30 }; System.Windows.Forms.Button ok_button = new System.Windows.Forms.Button() { Text = "确定", Top = 30, Left = 200 }; public string y; public windows2() { this.Controls.Add(title_label); this.Controls.Add(y_textBox); this.Controls.Add(ok_button); ok_button.Click += new EventHandler(ok_button_Click); } void ok_button_Click(object sender, EventArgs e) { y = y_textBox.Text; this.Hide(); } } |
//展现3 public class windows3 : System.Windows.Forms.Form { System.Windows.Forms.Label title_label = new System.Windows.Forms.Label() { Text = "结果" }; System.Windows.Forms.TextBox z_textBox = new System.Windows.Forms.TextBox() { Top = 30 }; System.Windows.Forms.Button ok_button = new System.Windows.Forms.Button() { Text = "完成", Top = 30, Left = 200 };
public void showValue(string s) { this.z_textBox.Text = s; }
public windows3() { this.Controls.Add(title_label); this.Controls.Add(z_textBox); this.Controls.Add(ok_button); ok_button.Click += new EventHandler(ok_button_Click); } void ok_button_Click(object sender, EventArgs e) { this.Hide(); } } |
public class Program { static void Main(string[] args) { myControl(); }
static void myControl() { //初始化数据对象 myData data = new myData();
//-输入x windows1 w1 = new windows1(); w1.ShowDialog();
//-输入y windows2 w2 = new windows2(); w2.ShowDialog();
//-计算 data.y = int.Parse(w2.y); data.x = int.Parse(w1.x); int value; value = myMaths.add(data);
//-显示结果 windows3 w3 = new windows3(); w3.showValue(z.ToString()); w3.ShowDialog(); } } |
第一步
第二步
第三步
|
面向流程开发基于配运行的程序
大学毕业后,干了一段时间律师,觉得无聊,于是决定改行做程序员
VB,VC,ASP,VB.NET,C#,一直没的再遇到一个让我激动的技术,
2005年时,我正在参考Shark用NET实现一个工作流平台,这时我接触了WF, 那时WF还没集成到NET中,是一个WinFX的组件,看到WF我就喜欢上这个家伙了.
后来我建议放弃Shark的思路,用WF做工作流平台.公司里所有人都反对,于是在WF与公司间,我选择了WF.
下面是一个用WF实现上面例子中的控制部分
[数据模型],[数据操作],[展现1],[展现2],[展现3],保持不变
先创建一组功能Avtivity
public partial class 初始化数据对象: Activity { public 初始化数据对象() { InitializeComponent(); }
[System.Diagnostics.DebuggerNonUserCode] private void InitializeComponent() { this.Name = "初始化数据对象"; } protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { this.data = new myData(); return base.Execute(executionContext); }
public static DependencyProperty dataProperty = DependencyProperty.Register("data", typeof(myData ), typeof(初始化数据对象));
[DescriptionAttribute("data")] [CategoryAttribute("data Category")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public myData data { get { return ((myData )(base.GetValue(初始化数据对象.dataProperty))); } set { base.SetValue(初始化数据对象.dataProperty, value); } } } | |
public partial class 输入x: Activity { public 输入x() { InitializeComponent(); }
[System.Diagnostics.DebuggerNonUserCode] private void InitializeComponent() { this.Name = "输入x"; }
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { windows1 w1 = new windows1(); w1.ShowDialog(); this.data.x= int.Parse(w1.x); return base.Execute(executionContext); } public static DependencyProperty dataProperty = DependencyProperty.Register("data", typeof(myData), typeof(输入x));
[DescriptionAttribute("data")] [CategoryAttribute("data Category")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public myData data { get { return ((myData)(base.GetValue(输入x.dataProperty))); } set { base.SetValue(输入x.dataProperty, value); } } } | |
public partial class 输入y: Activity { public 输入y() { InitializeComponent(); }
[System.Diagnostics.DebuggerNonUserCode] private void InitializeComponent() { this.Name = "输入y"; }
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { windows2 w2 = new windows2(); w2.ShowDialog(); this.data.y = int.Parse(w2.y); return base.Execute(executionContext); }
public static DependencyProperty dataProperty = DependencyProperty.Register("data", typeof(myData), typeof(输入y));
[DescriptionAttribute("data")] [CategoryAttribute("data Category")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public myData data { get { return ((myData)(base.GetValue(输入y.dataProperty))); } set { base.SetValue(输入y.dataProperty, value); } }
} | |
public partial class 计算: Activity { public 计算() { InitializeComponent(); }
[System.Diagnostics.DebuggerNonUserCode] private void InitializeComponent() { this.Name = "计算"; }
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { value = myMaths.add(data); return base.Execute(executionContext); }
public static DependencyProperty valueProperty = DependencyProperty.Register("value", typeof(int), typeof(计算));
[DescriptionAttribute("value")] [CategoryAttribute("value Category")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public int value { get { return ((int)(base.GetValue(计算.valueProperty))); } set { base.SetValue(计算.valueProperty, value); } }
public static DependencyProperty dataProperty = DependencyProperty.Register("data", typeof(myData), typeof(计算));
[DescriptionAttribute("data")] [CategoryAttribute("data Category")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public myData data { get { return ((myData)(base.GetValue(计算.dataProperty))); } set { base.SetValue(计算.dataProperty, value); } }
} | |
public partial class 显示结果:Activity { public 显示结果() { InitializeComponent(); }
[System.Diagnostics.DebuggerNonUserCode] private void InitializeComponent() { this.Name = "显示结果"; } protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { windows3 w3 = new windows3(); w3.showValue(value.ToString()); w3.ShowDialog(); return base.Execute(executionContext); } public static DependencyProperty valueProperty = DependencyProperty.Register("value", typeof(int), typeof(显示结果));
[DescriptionAttribute("value")] [CategoryAttribute("value Category")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public int value { get { return ((int)(base.GetValue(显示结果.valueProperty))); } set { base.SetValue(显示结果.valueProperty, value); } }
} |
创建控制流程
在WorkflowRuntime中创建实例,并运行实例
class Program { static void Main(string[] args) { using(WorkflowRuntime workflowRuntime = new WorkflowRuntime()) { AutoResetEvent waitHandle = new AutoResetEvent(false); workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) {waitHandle.Set();}; workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); };
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(example5.myWorkflow)); instance.Start();
waitHandle.WaitOne(); } } } |
|
为什么需要使用WF
下面,说一下为什么需要使用WF
说实话,我不是没见过世面,工作流的理轮,设计模式的理论我也学过一些
为什么需要使用WF,要实现流程控制我们也可用一些经典的设计模式去实现,比如下面的例子
职责链方式实现流程控制
引擎设计
//引擎 public class wfEngine { //实例池 protected System.Collections.SortedList InstancePool; public wfEngine() { InstancePool = new System.Collections.SortedList(); }
//添加实例到引擎 public string AddInstance(wfTemplet Instance) { InstancePool.Add(Instance.InstanceID, Instance.CurrentNode); return Instance.InstanceID; }
//工作流下移一结点 public bool ExecuteNextNode(string InstanceID) { if (InstancePool.Contains(InstanceID)) { if (((wfNode)InstancePool[InstanceID]).NextNode != null) { InstancePool[InstanceID] = ((wfNode)InstancePool[InstanceID]).execute(); return true; } else { ((wfNode)InstancePool[InstanceID]).execute(); InstancePool.Remove(InstanceID); return false; } } return false; }
// 一次执行完实例的所有结点 public void AutoExecute(string InstanceID) { while (ExecuteNextNode(InstanceID)) { AutoExecute(InstanceID); } }
//得到实例状态 public string getInstanceState(string InstanceID) { if (InstancePool.Contains(InstanceID)) { return ((wfNode)InstancePool[InstanceID]).NodeId; } return null; }
//得到引擎内的所有实例 public System.Collections.SortedList getInstances() { return this.InstancePool; } } |
工作流模板
//工作流模板 public class wfTemplet { public string InstanceID;//实例ID public wfTemplet(string InstanceID) { this.InstanceID = InstanceID; } public wfNode CurrentNode; } |
结点模板
//结点模板 public abstract class wfNode { public string InstanceId;//实例ID public string NodeId;//结点ID
public wfNode(string InstanceID, string NodeId) { this.InstanceId = InstanceID; this.NodeId = NodeId; }
//下一结点 public wfNode NextNode;
//执行区 public abstract wfNode execute(); } |
代码结点模板
//条件表达式类 public class conditionExpression { public object leftExpression;//左表达式 public object rightExpression;//右表达式
//比效方法 //可以跟据需要自定义左、右表达式,并重载比效运算符 public bool contrast() { if (leftExpression.Equals(rightExpression)) { return true; } else { return false; } } }
//条件结点模板类 public class conditionNode : wfNode { //构造函数 public conditionNode(string InstanceID, string NodeId) : base(InstanceID, NodeId) { }
public conditionExpression expression;//表达式对象 public wfNode ElseNode;//否则结点
//执行区 public override wfNode execute() { if (expression.contrast()) { return this.NextNode; } else { return this.ElseNode; } } } |
条件结点模板
//条件表达式类 public class conditionExpression { public object leftExpression;//左表达式 public object rightExpression;//右表达式
//比效方法 //可以跟据需要自定义左、右表达式,并重载比效运算符 public bool contrast() { if (leftExpression.Equals(rightExpression)) { return true; } else { return false; } } }
//条件结点模板类 public class conditionNode : wfNode { //构造函数 public conditionNode(string InstanceID, string NodeId) : base(InstanceID, NodeId) { }
public conditionExpression expression;//表达式对象 public wfNode ElseNode;//否则结点
//执行区 public override wfNode execute() { if (expression.contrast()) { return this.NextNode; } else { return this.ElseNode; } } } |
业务程流
public class 我的业务程流 : wfTemplet {
public codeNode 结点A; //结点A:代码结点 public conditionNode 结点B; //结点B:条件结点 public codeNode 结点C; //结点C:代码结点 public codeNode 结点D; //结点D:代码结点 public codeNode 结点E; //结点E:代码结点 public 我的业务程流(string InstanceID) : base(InstanceID) { /* * 结点A * | * | * 结点B * (true)/ \(false) * / \ * 结点C 结点D * \ / * \ / * 结点E */
//结点A:代码结点 结点A = new codeNode(this.InstanceID, "结点A"); 结点A.Code += new codeMethod(结点A_Code); 结点A.CodeParameter = "wxwinter的一个测试";
//结点B:条件结点 结点B = new conditionNode(this.InstanceID, "结点B");
//结点B的条件表达式 conditionExpression 条件表达式 = new conditionExpression();
结点B.expression = 条件表达式; //绑定条件表达式到结点B
//结点C:代码结点 结点C = new codeNode(this.InstanceID, "结点C"); 结点C.Code += new codeMethod(结点C_Code); 结点C.CodeParameter = "结点C,条件的真结点";
//结点D:代码结点 结点D = new codeNode(this.InstanceID, "结点D"); 结点D.Code += new codeMethod(结点D_Code); 结点D.CodeParameter = "结点D,条件的假结点";
//结点E:代码结点 结点E = new codeNode(this.InstanceID, "结点E"); 结点E.Code += new codeMethod(结点E_Code); 结点E.CodeParameter = "完成";
//指定入口结点 this.CurrentNode = 结点A;
//设置结点关系 结点A.NextNode = 结点B; 结点B.NextNode = 结点C; 结点B.ElseNode = 结点D; 结点C.NextNode = 结点E; 结点D.NextNode = 结点E; }
//结点A:代码 private void 结点A_Code(wfNode sender, object data) { Console.WriteLine("实例ID:" + sender.InstanceId + ":" + sender.NodeId + ":" + data.ToString()); }
//结点C:代码 private void 结点C_Code(wfNode sender, object data) { Console.WriteLine("实例ID:" + sender.InstanceId + ":" + sender.NodeId + ":" + data.ToString()); }
//结点B:代码 private void 结点D_Code(wfNode sender, object data) { Console.WriteLine("实例ID:" + sender.InstanceId + ":" + sender.NodeId + ":" + data.ToString()); }
//结点E:代码 private void 结点E_Code(wfNode sender, object data) { Console.WriteLine("实例ID:" + sender.InstanceId + ":" + sender.NodeId + ":" + data.ToString()); } } |
使用
class Program { static void Main() { wfEngine 引擎 = new wfEngine();
//实例03 我的业务程流 obj1 = new 我的业务程流("03"); obj1.结点B.expression.leftExpression = 100; obj1.结点B.expression.rightExpression = 100;
//实例04 我的业务程流 obj2 = new 我的业务程流("04"); obj2.结点B.expression.leftExpression = 99; obj2.结点B.expression.rightExpression = 100;
//将实例添加到引擎 引擎.AddInstance(obj1); 引擎.AddInstance(obj2);
while (true) { System.Console.WriteLine("---------------------------------"); System.Console.WriteLine("引擎中的实例:"); foreach (object obj in 引擎.getInstances().Keys) { string insID = obj.ToString(); string insStd = 引擎.getInstanceState(insID); System.Console.WriteLine(insID + ":" + insStd); } System.Console.WriteLine("---------------------------------"); System.Console.WriteLine("请输入要下一步的实例号:[exit为退出]");
string s = System.Console.ReadLine(); if (s == "exit") { break; } 引擎.ExecuteNextNode(s);
} }
} |
数据的持久化
光实现流程控制是不够的,我们还需要流程的持久化功能,这也不难,用如下方式就可以了
class Program { static void Main(string[] args) { myData data1 = new myData(); data1.x = 123; data1.y = 456; data1.saveToFile(@"c:\data.xml");
myData data2 = new myData(); data2.loadFromFile(@"c:\data.xml"); System.Console.WriteLine("data2[x:{0},y:{1}]",data2.x,data2.y );
System.Console.Read(); } }
//数据 [System.Serializable] public class myData { public int x { get; set; }
public int y { get; set; }
public void saveToFile(string path) { System.Xml.Serialization.XmlSerializer xs; xs = new System.Xml.Serialization.XmlSerializer(typeof(myData)); System.IO.FileStream file = new System.IO.FileStream(path, System.IO.FileMode.Create); xs.Serialize(file, this); file.Flush(); file.Close(); }
public void loadFromFile(string path) { System.Xml.Serialization.XmlSerializer xs; xs = new System.Xml.Serialization.XmlSerializer(typeof(myData)); System.IO.FileStream file = new System.IO.FileStream(path, System.IO.FileMode.Open); myData data = (myData)xs.Deserialize(file); this.x = data.x; this.y = data.y; file.Close(); } } |
如果自已做,还要做些什么
为了修改方便,我们应该提供一个可以基于配置文件运行流程的接口,这个也可实现,当时我就已经做出来了
为了设计方便,我们应该提供一个可视化设计流程的UI,这个也可实现,当时我就已经做出来了
如果不是单机运行,我们还应该提供一个网络访问的接口,这个也可实现,当时我就已经做出来了
还有,流程可能要对数据库操作,我们应该提供一套事务处理案,
在这里,我遇到了问题,当时我的唯一选择是COM+,在用VB开发时,我就用COM+ ,
其实COM+并不好用,我一直想有一个DCOM 与 COM+ 结合的东西,而我当时的选择是COM+ 与 Remoting ,我不喜欢这个组合,
当时我想回到以前用VB开发DCOM的方式做,而组件事务部分就不要用,用传统的数据库事务.
这时,WF出现了,WF提供了上面我所说有全部功能,另外WF + WCF 的组合是我非常欢的(早期我的例子都是WF+ Remoting的,2007年后的例子都是WF+ WCF的)
而另一个成员WPF也不错,让我找到了xml + xslt 的感觉,对了,还有点 DHTML behaviors 的感觉,(跑题了,不说了)
总结
我们为什么需要WF,因为不选WF,有很多功能都要自己去实现,很麻烦
除非
一,你要实现的这个功能确实太简单
二,你把这个功能的实现过程想的太简单