软件需求包括三个不同的层次:业务需求,用户需求和功能需求(也包括非功能需求)。售前人员用PowerPoint和Word编写客户的业务需求,为客户编写蓝图;项目经理则用Word编写用户需求规格说明书;而系统架构师又会采用UML 等另外一套建模技术对用户需求进行系统分析和设计。
除此之外,出于种种原因,客户的需求几乎肯定是要频繁发生变化的,哪怕是签了板上钉钉的合同,实施一个软件项目不可能总是陷入到PPT或者是Word文档的修改当中。如果有一个建模工具,能够由这几类人员统一使用,而且随着客户需求变化,多个模型之间也可以相互转化,再加上结合MDA/MDD 思想,这个工具能够自动生成一些能够减少程序员重复劳动的代码,那将能够极大提高软件开发企业的开发效率,使得应用软件做到真正“随需应变”。这恐怕也是软件公司梦寐以求的“银弹”。
但是,即使是UML创始人之一的James Rumbaugh 也说UML在对业务的描述上确实是有缺陷的,这些缺陷源于它并非为描述业务而设计。但是,通过引UML的扩展机制和UML2变化最大的Activity Modeling,还是为业务建模和多种模型之间的相互转化带来了一丝曙光。
本文重点在于讲述如何用UML2和GEF/EMF实现这个捕获企业需求的建模工具上,而不是讲述如何用UML2进行企业建模,所以本文的重点将放在UML2元模型和GEF/EMF具体技术上,用UML2作为理论依据把企业业务需求和他们整合在一起,以实现模型驱动思想的开发。我们用UML2的Activity Model作为我们例子的元模型,EMF作为具体实现模型,GEF作为我们的表示层,这就是UML2、EMF和GEF三者之间的关系。
这是一个很简单的采购审批流程,采购员提出采购申请,录入采购申请单(输出采购申请单),采购部门处长、部长或者具有采购审批权限的审批人,对采购申请单进行审批(输出是采购订单)。审批通过,则采购申请单自动生成采购订单,审批不通过,则退回采购员,采购员修改原采购申请单,重新提交。
下面采用UML2和GEF/EMF实现这个业务建模工具(而不是一个用来画工作流的工具)。
企业建模有很多建模方法,如:ARIS 、IDEF 和 UML。为了使业务模型能够更好的转化为信息系统分析模型,所以我们采用面向对象UML技术来描述一个业务。
下面将结合UML2的Activity Model来解释上述业务建模流程。活动图是UML所有图中变化最大的一种。UML 1.5 版本从早期版本中继承了状态机的概念,并将其改进为流程图,称之为活动图。令人遗憾的是 ,状态机的潜在含义限制了其明确意图,这使得用户感到很困惑。特别是那些没有面向对象概念的用户更对UML 1.x 的活动模型无所适从。类似的情形还涉及到UML 1.5 中包含的那些控制流和数据流模型。基于以上这些经验,UML2重新定义了Activity Model,并且和UML1.5的Action Model整合在一起。活动图的目的也发生了相当大的变化,它本来用于描述工作流程,现在它也包含一些必须的新特性使得它可以支持工作流程的自动化(automation)。原来的活动概念(Activities),改称动作(Action)。活动成了一个更高层次的概念,它包含一个动作序列。因此一个活动图展现了一系列的动作,这些动作一起组成了活动。
从图3中我们可以看到,Basic Activities的继承分支有两个方向,主要的一个是Structured Activities,用于软件建模(对应的类名是Action),另外的一个分支(Intermediate and Complete Activities)则用于一般过程建模。
UML2 活动(Activity)中包含有由边连接起来的组成完整流程图的节点(Node)。一个Activity可以包含多个Action。Activity的结点(Node)分为三大类:动作结点(Action Node)、控制结点(Control Node) 和 对象结点(Object Node)。动作结点主要是处理它接收到的控制流和数据值,或者提供这些动作和数据给其他动作;控制结点主要是路由控制流和数据值(比如判断框);对象结点主要用于存储临时数据,在编程方面,就是一个方法的参数对象。
我们再来看看采购订单流程业务模型中所涉及到的几个概念:
1、业务员/采购审批人员:在业务建模中我们称为业务角色(business worker)。业务角色是在业务中发挥作用的人的抽象,完成特定的工作,操纵业务实体,和其他业务角色交互。
2、采购申请单/采购订单:在业务建模中我们称之为业务实体(Business Entity)。在业务模型中,业务实体代表业务角色处理或使用的“事物”(A business entity represents a "thing" handled or used by business workers.)。航空公司今天打折,明天又不打,还有明折、暗折。可是机票从来没见有什么大的变化,从来也只有那几样属性:价格、航班、出发地、目的地。所以业务实体是比较稳定的。一般而言,一个好的业务实体不包含关于其使用主体和使用方法的信息(RUP)。在UML2中,它与Activity Model的Object Node相对应。在实际软件建模的时候,Business Entity对应着域模型(Domain Model)。
3、输入采购申请单/审批采购申请单:对应UML2 Activity Model中的Action;
4、判断框:对应UML2 Activity Model中Control Node之一的Decision;
5、控制流和信息流:对应UML2的Control Flow和Information Flow。
整个一个采购流程则对应UML2一个Activity。
我们利用Eclipse插件eclipseuml (http://www.omondo.com/download/index.html)对上述业务模型所涉及到的business worker 、Action、Business Entity、Decision、Control Flow和Information Flow等元素进行EMF建模。
我们用Element作为Business Worker 、Action、Business Entity、Decision的基类。抽出这些元素在图形中所共有的height、name、caption、width、x坐标、y坐标等基本信息。其中,Condition类表示Decision,Activity类 表示Action, Business Worker 类表示业务模型中的Business Worker,Business Entity类表示表示业务模型中的Business Entity,。对于Connection、Node、Diagram、Point、Dimension等类,它们是由于创建GEF应用程序所需要的辅助类。由于我们是在探讨如何对业务模型、软件模型统一建模,采用UML2作为我们的建模理论基础,如果要完善这个系统,这将是一个非常浩大的工作,所以我们并未严格按照UML2的Action的定义来对Action建模,比如在UML2中,Action有输入、输出,叫Pin,输入叫InputPin, 输出叫OutputPin。Pin 是一种 object node,在流中用于存储临时数据.
当我们用eclipseuml,创建EMF Class Diagram的时候,eclipseuml会为我们自动生成.ecd 、model.ecore和 .genmodel 三个文件。我们建好自己的EMF模型以后,就可以用.genmodel自动生成Model对应的Java代码了。
有了EMF模型,我们既可以利用EMF的代码生成工具得到一个可用编辑器(有兴趣的可以参照Merlin开源项目 http://sourceforge.net/projects/merlingenerator/ ),也可以自己编写一个GEF编辑器,让GEF利用EMF构造的模型。GEF的设计没有对模型部分做任何限制,也就是说,我们可以任意构造自己的模型,唯一须要保证的就是模型具有某种消息机制,以便在发生变化时能够通知GEF(通过EditPart)。这里我们用后一种方法作为自己的例子。
步骤一:生成我们自己的业务建模视图:
我们在plugin.xml文件里面加入:
<extension point="org.eclipse.ui.perspectives">
<perspective name="业务建模" class="org.bizsolution.jetblue.ui.perspective.ui.BusinessModelingPerspective"
id="org.bizsolution.jetblue.ui.perspective.BusinessModelPerspective"
icon="icons/bus_lvl_model_pers.gif">
</perspective>
<perspective
name="设计建模"
class="org.bizsolution.jetblue.perspective.ui.DesignModelingPerspective"
id="org.bizsolution.jetblue.perspective.ui.DesignModelPerspective"
icon="icons/bus_lvl_model_pers.gif">
</perspective>
</extension>
步骤二:生成自己的TreeView:
<extension point="org.eclipse.ui.views">
<view name="业务建模" icon="icons/buslvlmodelnav.gif" class="org.bizsolution.jetblue.ui.views.businessmodeling.view.NavigationTreeEditorView"
id="org.bizsolution.jetblue.ui.views.businessmodeling.view.NavigationTreeEditorView" />
</extension>
步骤三:生成自己的GEF编辑器:
<extension point="org.eclipse.ui.editors">
<editor class="org.bizsolution.jetblue.ui.BlueBirtEditor"
contributorClass="org.bizsolution.jetblue.ui.JetBlueEditorActionBarContributor"
default="true"
extensions="jbm"
icon="icons/shapes.gif"
id="org.bizsolution.jetblue.ui.BlueBirtEditor"
name="Business Model"/>
</extension>
步骤四:当模型用EMF实现,EditPart应实现org.eclipse.emf.common.notify.Adapter接口,因为EMF的每个模型对象都是Notifier,它维护了一个Adapter列表,可以把Adapter作为监听器加入到模型的这个列表中。
public void notifyChanged(Notification notification) {
int type = notification.getEventType();
int featureId = notification.getFeatureID(ModelPackage.class);
if (type == Notification.SET) {
switch (featureId) {
case ModelPackage.JET_BLUE_ELEMENT__X:
case ModelPackage.JET_BLUE_ELEMENT__Y:
case ModelPackage.JET_BLUE_ELEMENT__WIDTH:
case ModelPackage.JET_BLUE_ELEMENT__HEIGHT:
case ModelPackage.JET_BLUE_ACTIVITY__NAME:
case ModelPackage.JET_BLUE_ELEMENT__CAPTION:
refreshVisuals();
break;
}
} else if (type == Notification.ADD || type == Notification.REMOVE) {
switch (featureId) {
case ModelPackage.JET_BLUE_ELEMENT__SOURCE_CONNECTIONS:
refreshSourceConnections();
break;
case ModelPackage.JET_BLUE_ELEMENT__TARGET_CONNECTIONS:
refreshTargetConnections();
break;
}
}
}
步骤五:初始化我们的Palette , 加入Business Worker 、Action、Business Entity、Decision等元素。
PaletteDrawer businessProcessDrawer = new PaletteDrawer("Business Process");
CombinedTemplateCreationEntry component = new CombinedTemplateCreationEntry ("Business Worker", "Create an Business Worker", BusinessWorker.class, new CreationFactory() {
public Object getNewObject() {
return ModelFactory.eINSTANCE.createJetBusinessWorker();
}
public Object getObjectType() {
return null;
}
},BlueBirtPlugin.getImageDescriptor("icons/swimminglanec16.gif"), BlueBirtPlugin.getImageDescriptor("icons/businessworker.gif"));
businessProcessDrawer.add(component);
….
….
这样,我们就用GEF/EMF建立了一个企业业务需求捕获模型的工具。
让我们走的更远
我们用GEF/EMF建立了一个业务需求捕获模型工具,但是有了这个工具,距离我们的理想目标“软件建模和业务建模互相转化”差距还是很远的。我们可以继续完善这个工具,继续基于UML2的理论,创建类图,序列图和用例图等等。事实上,Eclipse组织也有一个开源实现UML2的项目。有兴趣的可以关注它。
客户的需求总是在不断的发生变化,使我们不得不考虑新一代的基于模型驱动开发的一些方法和技术,使得软件的生命周期更长一些,更客户化一些,更可以定制一些。本文摸索性的从技术上提出业务建模和软件建模相互转化的一些话题,希望能够得到大家的批评和指正。
参考资料
1、 UML 2.0 Superstructure Specification05-07-04
2、 China UML--软件和需求的实践(4-1)业务建模时期
声明:该文章已发表于《程序员》2006年第五期,如要引用请注明出处。