首页 > 范文大全 > 正文

按需构造的工作流系统组织模型

开篇:润墨网以专业的文秘视角,为您筛选了一篇按需构造的工作流系统组织模型范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!

摘 要:工作流系统作为基础组件应该能够与应用程序灵活集成,在设计工作流系统中的组织模型架构时应重点考虑与应用系统的集成方式。设计基于工厂模式与反射技术的组件按需加载模型,降低软件系统间的耦合。实现工作流组织模型与不同类型的应用程序的良好集成。基于该技术实现的项目管理系统在多个企业得到成功应用。

关键词:工作流;工厂模式;反射;耦合;按需加载;

中图分类号:TP311文献标识码:A

1 引 言

随着工作流技术的快速发展与逐步成熟,越来越多的应用系统将其作为必需的基础部件。为了将工作流集成到应用系统中,许多公司都开发了自己的工作流产品。但是在开发过程中,一个需要重点解决的问题是如何实现工作流管理系统与应用系统的灵活集成。由于工作流管理系统是一个公共部件,因此,它应该能够很方便地与各种应用集成而又不破坏双方的设计架构,这实际上是如何降低工作流管理系统与应用系统的耦合度的问题。

在J2EE平台下,有几种技术可以很好地解决这个问题,如Spring框架、Avalon框架、PicoContainer轻量级容器等[6]。但在.NET平台下,却没有相应的框架产品。另外,出于对性能的考虑,应用程序中没有采用上述任何框架,因而需要设计一种足够灵活的组件集成模型。

2 耦合问题的分析

根据WfMC的定义,一个完整的工作流模型是由过程模型、组织模型和资源模型构成的一个有机整体[4]。实施基于工作流管理系统的应用时一个非常重要的任务就是将应用程序中的组织模型与工作流中的组织模型集成。但是,由于应用程序和工作流产品是由不同团队开发的,模型上的差异使得集成相当困难。通常采用的方式是在应用程序中利用工作流提供的接口将组织数据写入工作流系统中,以实现流程的工作指派。但这种方式导致组织数据在两个数据库中重复存放,需要考虑数据的完整性和一致性管理,非常繁琐。如图1所示。

重复意味着耦合[1],这种数据库的重复造成了两个系统间不必要的耦合,它势必要求在两个数据库之间保持一致,而完成这项工作是非常困难的。一个自然的想法是去掉工作流环境中的组织数据库而采用应用环境中的组织数据库作为统一的组织数据存储环境,这样就解决了数据的一致性问题。但是,在这种方式下,工作流中的组织模型组件需要访问应用环境的组织模型组件,从而导致工作流组件对应用程序组件的依赖,这显然是不行的。这是因为不同的应用环境可能具有不同的组织模型和接口,开发工作流系统时不可能预知将和哪个应用程序集成,因而也就无法预知应用程序的组织模型的接口和组件。即使通过制定统一的组织模型接口标准,还是需要在工作流组织模型中实例化应用系统的组织模型组件。见图2。

这实际上是一个如何延缓接口实现的问题,即在开发工作流组件时只依赖共同的组织模型接口编程,而组织模型的实例化则在集成具体应用时完成。

3 按需加载模型

在.NET 平台下基于工厂模式和反射技术的按需加载模型提供了对这个问题的一个解决方案。思路是:调用者通过工厂对象来实例化被调用组件,但由于被调用组件的可变性,不能在工厂代码中固化实例化具体组件的代码,因此我们借助于反射技术中组件的动态装载技术,通过配置文件设置要实例化的组件,再由工厂类读取配置,根据配置决定具体实例化哪个组件,这样就实现了组件的按需加载。

计算技术与自动化2007年6月第26卷第2期方 俊等:按需构造工作流系统组织模型3.1 工厂模式

在传统的编程方式中,控制权是由调用者掌握,即调用谁是由调用者决定的,因此,在调用者代码中就包含了创建被调用者实例的代码,这样就构成了调用者对被调用者的依赖。见下面的代码(以下代码都采用C#编写):

在类A的代码中定义了类B的引用变量,这种依赖是在编译期引入的(前期绑定)。根据文献[3],这种依赖是造成软件僵化(Rigidity)、脆弱(Fragility)的主要原因。DIP原则指出应该在调用者和被调用者间加入抽象接口,使调用者和被调用者都依赖于抽象接口,这样,只要接口保持不变,被调用者的改变不会影响调用者,从而解决了软件的僵化脆弱问题。见图3:

但是,引入抽象接口并没有将调用者和被调用者完全解耦,只是将两者间的依赖由前期绑定改成了后期绑定。在调用者代码中还存在直接创建被调用者实例的代码。见下面代码:假设IB是一个接口,类B实现了接口IB。

这种A和B的依赖关系导致了对组件B的调用的不可变性,如果存在多个实现了IB接口的类可以完成类似工作,在这种方式下就没有办法根据需要有选择地调用所需的类。GoF的《设计模式》中给出的工厂模式很好地解决了这个问题。

简单工厂模式[5]引入一个工厂类,负责根据需要来创建被调用者的实例,调用者通过工厂类获得调用者实例。这样,在调用者代码中就没有对被调用者的直接引用,从而实现了调用者和被调用者间的真正解耦。通常,工厂类时根据传入的参数来决定创建哪个调用者实例的。见图4:

但是工厂模式对于有些情况却无能为力,比如“耦合问题分析”一节中描述的组织模型调用问题:在编写工作流软件组件时无法预知将会和哪个应用程序集成,因此无法采用上述的工厂模式来实例化具体的应用程序中的组织模型组件。必须有一种机制使得工厂可以在运行时选择组件并对其进行实例化,也就是我们在工厂中不必固定地写入要实例化的类的名称,如图4中的B1、B2、B3那样。

这种机制可以通过.NET平台的反射技术实现。

3.2 在工厂模式中使用反射

使用反射技术可以动态地装载程序集,并从程序集动态地创建类型的实例[2]。将反射技术与工厂模式结合,就可以实现组件的按需加载。方法是:通过将组件的信息写入一个XML文件,在工厂类中读取配置文件并根据读取的组件信息动态装入组件,然后实例化所需类。由于组件可以是不同的团队根据公共接口标准实现的,因而也就实现了与不同应用系统的集成。

依照上述思路,将工厂模式中的工厂类扩展成一个服务容器,该容器根据配置文件动态装载组件,并将组件中的类封装成一个个服务存放在服务集合中。容器提供一个查找方法可以根据条件从集合中找到所需类的服务,返回给调用者,调用者通过服务对象可以获得所需的类的实例。注意,被封装的类必须实现公共的接口。见图5。

从图5可以看到,由于采用了反射的动态装载机制,调用者(A)与被调用者(B1、B2、B3)之间没有了依赖关系,同时工厂类也没有与任何具体的被调用者类存在依赖关系,这样工厂就可以实现对被调用者组件的按需装配。只要组件实现了IB接口,就可以通过配置文件将其作为服务装配到工厂中,调用者可以调用工厂类的方法(GetService)查找所需被调用者的服务,通过该服务提供的方法(GetInstance)可以获取被调用者类的实例。

工厂类以单例模式[5]实现,目的是保证服务容器的一致性。在其中实现一个静态方法CreateFactoryInstance,用于获得工厂实例。在工厂类的构造函数中读取配置文件,获得当前系统配置的组件信息,并将这些组件信息封装成一个个的服务,存放在集合Services中。在封装一个服务时需要有接口、实现类、程序集文件等信息,因此,在配置文件中每条配置信息需要有上述内容。下面是一个配置文件的例子。

其中,InterfaceName是接口的完全限定名,ClassName是实现类的完全限定名,AssemblyFile是程序集文件名。

在工厂类中集合Services存放的服务对象是Service的实例。Service类中存放有接口名、类名、程序集文件名,这些信息是在工厂封装服务时通过构造函数存入的。见下面代码:

为了让调用者可以获得所需的服务,工厂类中还提供了方法GetService,它根据调用者提供的接口名在集合Services中查找对应的服务。见下面代码:

3.3 组织模型的按需构造

有了上述的工厂,我们可以在工作流系统中定义组织模型的接口,并要求与之集成的应用程序实现这些接口,然后在配置文件中对这些信息进行配置,这样,在工作流系统中就可以通过工厂类对象动态获得应用程序的组织模型组件的实例,并通过这些实例完成对组织数据的操作。下面以组织模型中的部门为例说明其实现:

首先在工作流系统中定义接口IDepartment,然后在应用程序中实现该接口,假设实现类为Department,并且编译后的组织模型组件为Organization.dll,则配置文件的信息如上节所示。

当在工作流系统中需要访问组织数据时,可以采用下述代码获取Department的实例:

在工作流中对组织数据的访问完全是透明的,它不必在编译期连接确定的组件,而是通过在执行时动态装载特定组件实现对组织数据的访问。在本实例中我们并没指定应用程序是什么,它可以是工程项目管理系统也可以是ERP系统,只要实现了工作流中定义的组织模型接口,就可以将其写入配置文件让工作流系统调用。这样,极大地增强了工作流系统的灵活性,方便其与各种应用系统的集成。

4 结束语

通过将工厂模式与反射技术结合实现组件的动态加载,解决了工作流系统的组织模型与应用系统的组织模型的集成难题,使得基于不同数据库系统开发的工作流系统和应用系统可以很好的集成在一起。基于这一技术实现的工作流系统已在多个钢铁企业的工程项目管理系统中得到了成功的应用。

注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。