案例描述
有个公司想改善他们的信息系统。第一步是分析职工的培训程序,将一些任务自动化。
- 当一个职工向培训官申请培训的时候,一个培训程序就开始了。培训官将决定是否同意这位职工的培训申请。
- 如果培训官同意了职工的培训申请,培训官将会在目前可以负责的培训项目里寻找合适的培训项目。一旦职工决定了她所要接受的培训项目,培训官将会向教员登记。
- 如果职工中途停止了培训,它必须在最短的时间里通知培训官以便注销登记。
- 培训结束后,职工必须把一张自评和一张出席登记表一起提交给培训官。
- 培训官在把表单们提交给汇记服务前先进行检查。
注:UML in practice, P.Roques, Wiley, 2004 提供案例
主要方法
我们将使用下面的UML图表来进行讲解 :
类图用于定义代码框架, 以可以说成是整个类的声明。
在一开始,我们可以近似的说:
- 一个UML类图将成为一个C#类
- UML类图的属性将成为C#类的实例的变量
- 类图的操作方法将成为C#类的方法
大家会注意到navigable角色被实现为实例变量,就像属性一样,但它是却不是一个简单类型,而是一个用户自定义类型。这暗示了一个类的创建。
我将举一个简单的图示说明这些方法。
图A 一个订单类的框架代码 | |
|
交互图说明了类的方法的运作过程,特别是相互关联一些方法的调用次序。
接下来的这个图示说明了消息序号与C#方法实现代码的关系。
图B enregistrerEmprunteur(register borrower)方法的主体 | |
|
在这些例子之后,我将会给出一些具体的真实的例子。
从UML类图到C#框架代码
大家来看图C,注意一下“培训申请”类
图C 培训申请类的内部关系 | |
|
前面讲过的方法已经住足够把这张图表转换成C#框架代码。我们唯一要紧记得是我们必须添加一条导入语句来保证能够与其它包中的类建立联系(不论是用户自定义的包还是标准基类库)。
等价的C#框架代码在图D上。
图 D : 培训申请类的C#框架代码 | |
|
如果我们要为一个属性添加读写操作,根据封装类的方法,我们自然要为类添加一个属性,就像下面的代码:
public int propDateValidite { | |
get { return DateValidite; } | //这是propDateValidite属性的“读”操作 |
set { DateValidite = value; } | //这是propDateValidite属性的“写”操作 |
} |
现在让我们看看图E,注意里面的“培训”类。
图 E : 类的构成与它们之间的关系 | |
|
以前面的例子相比较, 又产生了一些附加的问题:
• 元素之间关系的概括
• 多重性:Theme(Topic)的<<1..*>>和Session的<<0..*>> {ordered}
前面的方法已经不适用了。我们已经看到如何用<<1>>(或<<0..1>>)的多重性来实现navigable联系,然而,如何将联系转换为<<*>>的多重性呢?
有个相当简单的原则:通过用一个具有特定属性的类型(如对象引用集合)来取代对单个对象的引用来实现<<*>>多重性。
正确地选择.NET framework提供的集合类型是困难的。虽然用C#创建manager arrays很容易,但这对于一个正确地解决方案来说是不必要的。一般来说,人们更喜欢使用像C#的ArrayList或HashTable这样的集合类型。
• 如果你想记住对象之间的次序,而且想用整数索引取得对象的话,就选择ArrayList;
• 如果你想用任意的关键字取得对象的话,就是用HashTable或SortedList。
这里有一些应付各种不同需要的解决方案:
图 F : UML联系到C#的转换 | |
|
对于Formation类,我们将会使用:
• 一个ArrayList来实现对Session的组织
• 一个HashTable来实现对Theme的组织而不是用一个简单的数组。我们使用大纲的名称作为限定词
通过以上的说明,我们可以写出这样的代码:
图 G : Formation类的C#框架代码 | |
|
结束语
把UML图表转变成代码是一件必须规范的敏感的工作。所以,对于一些语言来说,转换得到的代码与UML图表之间可能会有一些冲突。代码发生工具能自动进行UML与代码的转换工作,但它同时也会向对象编辑器提供一些不同的选择(例如ArrayList与HashTable)。