软件工程硕士UML建模 用EA工具创作一个Actuator-Sensor模式的顺序图并配文字解释

2) 理解 EA 界面布局和元素操作的一般技巧;

3) 熟悉 UML 中的各种图的建立和表示方法;

4) 掌握如何通过 EA 工具完成相关模型的建立

1. EA 开发环境的介绍

之后 可以选择新建一个项目。 茬新建项目时 系统会提示选择所需要的模型设计。

(2) 选择了所需要的模型之后 可以看到, 在界面的右侧出现了相应的导航栏 如下圖所

示, 在导航栏里面列出了刚才所选择的系统模型

(3) 假设选择用例建模, 那么可以从左侧的工具面板中拖拽出一个参与者 并为它命名。

这样在系统里面就多了一个叫做“用户” 的参与者

(4) 以同样的方式从左侧工具面板中拖曳一个用例, 命名为“用例一”

(5) 哃样通过拖拽的方式, 建立用例与参与者之间的关系 对这个关联关系, 我们还可

以设置更加细化的约束

2. 采用EA工具完成以下ATM示例系统的UML模型的建立。

通过 EA 工具完成相关 UML 图的绘制在建立过程中尝试理解模型元素,模型元素之间的关系

1.软件下载——首先在官网上下载好本佽实验的软件EA,安装好后建立ATM的项目并建立相应的视图

2.新建项目——一个名叫ATM.eap的项目勾选出合适的模型,并在模型下建立合适的包


4.分别為各子包建立需求

5.ATM系统功能性需求

通过网络查找相关资料了解有哪些工具可以支持UML模型与C++或JAVA或PYTHON代码的相互转换,并给出网络链接及说明

本次实验相对前几次来说没那么难,只是在使用新软件EA的过程中遇到了一下困难在参考一些视频讲解后了解到这个软件的使用方法和特性,后来我开始用它来建立行为模型和用例模型总的来说,本次实验是一个验证性的实验即使用UML工具进行验证UML建模实验,收获很多对自己的思维能力也有提升。

本文介绍使用EnterpriseArchtect进行建模是类图嘚使用方法。篇幅较长请慢慢阅读。示例中使用的EnterpriseArchtect的版本为13.0其他版本的区别也应该不大,请自行调整

启动EA后选择【New Project】菜单项,在出現的【New Project】对话框中输入文件名后按下【保存】按钮

为简单起见,在出现的【Model Wizard】中不做任何选择直接选取消。我们还是可以得到下面的笁程文件


注意右上角的【Modle】节点,就是工程的根节点

在Model节点的上下文菜单中选择【Add】-【Add View】菜单。就可以调出CreateNewView对话框具体如下图。


输叺Name并选择Icon Style这里不必太纠结,事后都可以改的比如IconStyle就可以通过DemoView节点的上下文菜单中的【Set View Icon】项目修改。

接下来我们从DemoView节点的上下文菜单中選择【Add Diagram】调出【New Diagram】如下的对话框。


输入/选择必要的信息

点击【OK】按钮,就可以得到一个名为Class Diagram1的类图画面大致如下。


添加新类的操作洳下图所示从软件的工具栏中向类图中拖动Class图标


释放鼠标后会自动出现类属性对话框。


在【General】分类页面中输入类名Person并确定Language中选中的是C++以後按下【确定】按钮。画面会变成以下的样子

这里选择C++有两个作用,一是决定生成代码的语言二是有些选项(比如私有继承)会随著本设定而改变。其实也不一定要问为什么做对的事情就好了。


除了左侧出现黄色的Person类方框以外右上部分的Model树上会出现一个Person节点。严格来讲这个Person节点才是我们在模型中增加的那个类。左边类图中的Person只是一个链接

为了说明这点,我们可以删除类图中的Person类这时画面会變成下面的样子。


类图中的Person类虽然不见了Model树上的Person还好好的在那里。



目前的【Drop as】项目的选项是Link会在画面上增加一个Person类的链接。


现在回复箌了删除前的状态没有损失任何东西。追加说明一点在ClassView中有了Person类,如果继续上面的操作EA会拒绝。

这还没有完我们继续向ClassView拖动Person节点,但这次我们选In


请同时关注ClassView的变化和Model树的变化我们可以继续增加实例,增加一个实例Model数的节点也会增加。它们目前名字相同但是是鈈同的实例,这个场景下就是不同的人。

我们还可以通过属性对话框来修改实例名由于篇幅和流量的原因,这里省略

到这里还没有唍,我们继续向ClassView拖动Person节点但这次我们选Child(Generalization)增加一个Person类的派生类,画面就会变成下面这样


你大概注意到了,软件为我们可以自动添加叻泛化连接线子类也可以重复添加,每次都是增加另外一个子类虽然目前的名称相同,但是都是不同的子类这一点可以从Model树上看到結果。

选择Model树上的对应节点打开上下文菜单,选择【Delete ‘?’】即可,这回可是真删要慎重!

属性是OO中的一个词汇,在C++语法中应該叫数据成员。这里我们尽量使用OO中的属性一词

打开属性窗口有两种方法:

1.双击类图中的对应类框图,选择【General】以后点击【Attributes】按钮。


2.從模型树中选择对应的类节点打开上下文菜单并选择【Attributes】菜单项。


无论哪种方法都可以打开下面的属性设定对话框严格讲这并不是属性自己的属性对话框,而是属性和操作共同的对话框本文只关注属性部分。


添加新属性的操作主要是在红绿两个矩形框中进行的我们茬这里只说明有(zhi)关(dao)的项目。

基本项目通过红框中的列表控件来设置

Name:变量名,可以自由输入文本。

Type:数据类型可以自由输入文本,也可以點从下拉菜单中选择在下拉菜单的最下面,还有一个【Select Type...】选项提供了从工程中选择类型的功能。但是选择的结果也只是作为文本保存起到的作用仅限于输入辅助。如果你期待变量类型和被参照的类型名联动那你想多了。

agePackage也是可选的,表示也没有问题但是在生成玳码时当作Public处理。

Initial Value:为属性设置初期值可以就地输入或打开对话框输入。区别不详

属性列表中有属性被选中时,可以设定该属性的扩展屬性

Static:表明该属性是静态属性,或称静态数据成员


Const:定义常量数据成员。


在本例中创建了三个属性(扩展项目部分省略表示):

作为上述操作的结果类图变成下面这个样子。


请注意观察在类图中属性的表达方式另外也可以看到SetAge和GetAge两个方法。

关于初期值的补充说明:

在基夲项目中有一个初期值InitialValue需要补充说明一下

在C++11之前这个项目只能应用于静态常量数据成员。

在C++11以后可以为每个变量设定缺省值。当构造函数的初始值列表中没有为数据成员制定初始值的时候编译器会利用这个缺省值来初始化数据成员。

也许有人会问操作和方法不是一囙事么?还真不是一回事

操作指明了目标对象状态的转换或返回给操作调用者值的查询。它有名称和参数列表包括返回参数。操作指萣了行为的结果而不是行为本身,行为可以是一个方法一次状态机转换或其他。

方法是一个过程它实现了一个操作,它有一个算法戓过程描述调用如果解析为一个方法,将导致该过程被执行

以上是ULM2.0对操作的方法的说明。你看懂了么反正我是琢磨了好一会。那我僦举个例子吧

说有一个驾驶者基类,它有有两个派生类分别是车主和小偷。驾驶者类声明了一个启动汽车的操作车主类使用(实现)的方法是拧车钥匙,小偷类使用(实现)的方法是直接接发动机电源线(电影里常有的)

怎么样,好点没下面继续今天的话题。

  1. 双擊类图中的对应类框图选择【General】以后,点击【Operation】按钮



无论哪种方法都可以打开下面的操作设定对话框。严格讲这并不是操作自己的对話框而是属性和操作共同的对话框。本文只关注操作部分


添加新操作的操作主要是在红绿蓝三个矩形框中进行的。和上篇文章一样我們在这里只说明有(zhi)关(dao)的项目

基本项目通过红框中的列表控件来设置。

Name:变量名,可以自由输入文本

Parameters:在参数设定部分详细说明,此处省略

Retun Type:数据类型,可以自由输入文本也可以点从下拉菜单中选择。在下拉菜单的最下面还有一个【Select Type...】选项,提供了从工程中选择类型的功能但是选择的结果也只是作为文本保存,起到的作用仅限于输入辅助这一点和属性类型一样。

Scope:设定操作的可视性从下拉列表中选择,一共有四个选项:Public/Protected/Private/PackagePackage也是可选的,表示也没有问题但是在生成代码时当作Public处理。

操作列表中有操作被选中时可以设定该操纵的扩展屬性。

Concurrency:用于自定操作的并发属性可能的选项有:

  1. sequential:同时只能有一个调用发生。如果并发调用发生则结果不保证。

  2. guarded:允许并发调用发生但同时只允许一个调用执行。

  3. concurrent:允许并发调用发生并保证可以正确地并发执行。

Virtual:用于指定抽象操作(虚函数)

Static:表明该操作是类操作(静态函数),而非实例操作

参数定义主要是通过蓝框中的【Parameters】表单来进行的。可以定义多个参数并设定他们的属性。方法和类设定屬性的方法基本一致此处省略。

我们试着为Person类追加了两个方法一个是静态方法GetMarryAge,一个是虚函数ShowPerson类变成了如下的样子。

可以看到静态方法GetMarryAge的下面有一条横线而Show操作被表示成斜体。这就是UML中静态方法和抽象操作的表达方式

如果这还不够,还可以再往前走一步生成代碼。在Person类上点击鼠标右键调出上下文菜单选中【Code Engineering】-【Generate 
Code】可以调出如下的生成代码对话框


在选择路径之后,按下【Generate】按钮我们既可以得箌以下代码。



不做重复的事情这才是正确的方法应该有的样子。

模板和泛型编程也是C++中很重要的一部分相信很大一部分程序员都用过某种容器类。但一般来说也就是用用而已并不会自己构建类模板或者在建模中使用类模板。

接下来介绍EA中类模板的创建类模板和使用类模板的方法

假设我们要创建一个映射类(假设而已,可别真去创建)MyMap它有两个参数,一个是Key一个是元素T。

首先创建一个普通的类設定类名为MyMap。


一定有人在输入类名的时候直接输入MyMap<class Key, class T>这时候生成的类图就像下面这样。


看起来也是那么回事但是并不能生成正确的代码。所以还是回到原先的轨道上来吧只要输入MyMap就好。


按下【确定】按钮返回后类图会变成下面这样。



作为例子接下来利用MayMap实例化一个类洺为PersonMap的类负责管理从整数到Person*的映射。

首先创建一个普通的类名为PersonMap。



然后从PersonMap类向MyMap类拖动鼠标以建立两个类的连接关系。


鼠标双击《bind》連接线打开属性对话框并选择【Binding】分类然后按下【Add】按钮在【Parameter Substitution(s)】列表中添加参数。


如上图所示Formal列可以选择Key和T参数。它们都是在MyMap类模板Φ定义的继续操作,指定Key和T参数的内容

类图会变成下面这样。请关注红圈中的变化



生成的有效代码很少,但这确实是正确的代码茬UML中这种方式叫显示绑定。

在定义了类属性类操作等限制在单个类内部的内容之后,接着说明类之间的关系今天是关联的基础篇。

关聯是两个或多个特定类之间的关系它描述了这些类的实例之间的连接。在问题陈述中关联经常以动词(或动宾)形式出现。

比如学生囷老师之间的关联如果以学生为起点,老师为终点那么这种关联就可以称为获取知识(AquireKnowledge)。如果以老师为起点学生为终点,那么这種关联就教授知识(TeachKnowledge)有教就有学,一体两面

关联本质上都是双向的。但是在读的时候要按从起点到终点的方向来读


关联就是连接Student類和Teacher类之间的那条线,上面带有关联名AquireKnowledge下面介绍关联的表示/设定方法。

在增加关联关系之前首先打开类图并增加两个类:Student和Teacher。

接下来點击工具栏中的Associate图标(如下图)然后在Student类上按下鼠标并拖动鼠标到到Teacher类后释放。这里的方向是有意义的拖动开始的类就是关联的起点。


在生成的直线上双击鼠标以打开如下的AssociateProperty对话框


?接下来选择Role(s)分类,在SOURE和TARGET两边的列表中都可以看到Multiplicity项目这个项目叫多重度,后面会讲箌先都输入选择【*】。

这样就可以得到本文一开始的那张图了

多重性指定了一个类与其关联类的单个实例可能相关的实例数目。也不知道为什么这种定义总是那么难以理解还是结合上面的例子来说明吧。先假设这里的一个类是Student类那么它的多重性就指定了一个Teacher类的实唎可能与多少个Student类的实例相关。

区间还可以一个单独的整数来表示


有两个多重度的设定值。首先Student类侧的1表示的是一个Book类的实例只能和1個Student类的实例相关。Book类则为[0..*]表示一个Student类的实例可以和0到无限多个Book类的实例相关

我们也可以给关联的两端指定名称,例如在上面的Has关联中鈳以指定Student端的名称为owner,指定Book端的名称为belongings

关联端名的设定也是通过下面的AssociationProperty对话框来进行的。


设定关联端名以后类图就变成下面这样。


关聯端名一般以名词出现大多数场合关联端的命名会比关联的命名更容易一些。一旦指定了关联端名就可以省略关联名。

昨天的文章算昰关联的基本内容不大好理解,但是非常重要对于面向对象的建模,识别类当然是第一步接下来就是要识别类之间的关系,也就是關联可能会觉得有点虚,但是这是设计向上游发展的表现请务必认真体会并加以练习。

当某个关联端的多重度被指定为一以上时并沒有强调这些对象是不是有序的,也没有明确对象的值是不是可以重复这样的建模结果不够精确。其实很多场合是需要确定这些信息的在UML中,把这种信息成为有序性有序性关键词可以放在属性串的后面。

下面就以一个事件处理系统为例来说明

首先是按照发生先后处悝事件的情况,这时候事件是按照发生的时间次序排列(Ordered=True)的又因为同样的事件可能多次发生,所以队列中的值是可以重复(Allow Duplicates=True)的这种情况UML称の为{sequence},类图是下面这样的


另一种情况是按照事件优先级进行处理。这时候需要两方面的信息一个是EventHandler,管理所有发生的事件这些事件昰无序(Ordered=False)的,允许重复(Allow Duplicates=True)的;另一个是优先级信息队列EventPriorityQueue这个队列管理的是事件的优先级,是有序(Ordered=True)的不允许重复(Allow


接下来说明这两種信息的设定方法。进入关联端的设定对话框后通过下图红框中的项目,就可以分别设定是否有序和是否允许重复的选项了有一点需偠注意的是,只有在指定了多重度以后设定结果才会在类图中表示出来。


一共有两个设定项目四种组合,归纳起来就是下面这张图


伱一定注意到左下角的空白,UML并没有像其他三种情况一样给个说法而是作为初始(缺省)状态,在这个状态下元素是无序的(Ordered=False),同時每个元素又是唯一(Allow Duplicates=False)的这实际上就是集合。

正如可以使用属性描述类的对象一样也可以用属性来描述关联。UML用关联类来表示这样的信息关联类(association class)是一种关联,也是一个类

也不知道你是懂了呢还是懂了呢?还先从一个简单的例子开始说起吧

有一个温度控制系统,通过传感器测量温度传感器的输出是1v到5v,对应的温度为0到100摄氏度

控制器每0.1秒获取一次温度值,然后根据实际温度和期望的温度的偏差来决定输出值计算的周期为1秒,输出值的范围为0%到100%这个输出值发送给一台加热器来控制温度。

加热器的控制端在输入1v时的输出功率為0KW输入5v是输出功率为10KW。

这个系统应该如何建模呢先来第一步,识别类和关联


接下来将全部信息都反映到模型上。


不要被满篇的属性嚇倒耐心地,慢慢地读下去你会理解的。

谢谢你坚持读到这里回头来审视一下模型,有没有发现什么问题

是的,Controller类太大功能也呔多了。

这个问题的解决方案就是本文的话题:关联类当关联足够复杂,复杂到必须需要利用属性来描述细节利用操作来定义动作的時候就该关联类出场了。

在本例中取得温度值(GetTemperature)输出(SetOutput)两个关联,要进行线性变换各自需要四个属性(实际上还应该有操作),嘟可以定义为关联类就像下面这样。


前面废了那么多口舌到主角的时候反而简单了。

如果要总结的话关联类的内容就是补充描述关聯的那些信息

从一个例子开始今天的说明

假设有一个系统,收到外界的事件通知以后根据设备Id,将事件转发给适当的设备按照之湔的说明我们可以建模如下。


系统按照以下方式运行:

为了提高检索速度我们将SendEvent关联的Device端的有序性设定为{ordered},即:结构有序,而且在这个列表中每个Device只能出现一次

我们知道,有序性为{ordered}的数据结构可以是数组,也可以是链表查询是一般采用的线性查询。这种设计可以实现功能而且被大量使用着。

应该有很多人想到了还不够快,可以哈希表B树嘛!对了就是这个。我们今天的话题:限定关联利用限定關联以后,类图会变成下面这个样子


进一步讲,引入deviceId限定符以后除了通过deviceId取得唯一的Device这件是意外,它还附带了另外的含义:应该让这種操作更有效率差不多就等于要求采用更有效率的数据结构。

限定关联还是通过关联端属性设定对话框进行的


图中有两处变化,一是紅框中Qualifiers项目设成了deviceId而是绿框中多重度从“*”改到了1。

类和类之间除了存在关联/聚合/组合这种协作关系以外,还有泛化关系也就是C++中嘚继承关系。

泛化是指一个较特殊的类到一个较普通的类之间的关系较特殊的类也叫子类(subclass);较普通的类也叫超类(superclass)。子类继承了超类的所有特性(属性和操作)任何使用超类的地方,都可以用子类代替

泛化表示为从子类到超类的实线,超类端带有空心三角形


茬本例中,File类的功能已经很完整可以独立使用,但是我们需要支持文本文件和Utf文件的行读写功能于是增加了两个子类TextFile和Utf8File,它们一方面完整继承了File的所有特性,一方面又为用户提供了利用者需要的读写文本文件和Utf8文件的便利功能

这种泛化关系虽然可以满足利用者的需求,泹是没有人会在使用File的地方替换使用TextFile或者Utf8File而是把它们作为另外的类来使用。还有一点:很难找到漂亮的方法避免用户使用File类的Write/Read方法带来嘚混乱可以说这种泛化是没有经过认真设计的泛化,或者说是被动的泛化

还有另外一种情况,在设计时就考虑好超类子类的分工,囲同的部分由超类实现特殊的部分由子类实现。


在上图中图形尺寸,位置的处理由Shpe类负责;表示的部分则在Shape定义Show操作具体的Show方法由各个子类实现。因为Shape类没有实现所有的功能所以不应该被实例化。关于这一点UML提供了方法,就是将Shape定义为抽象类在EA中表示为斜体的類名。设定方法是在类属性的【detail】页中选中Abstract选项。具体如下图:


前面讲到了抽象类和具象类其中抽象类是不能被实例化的类。这即可能是因为类的实现还不完整(如缺少某些操作的方法)也可能是因为功能不完整而不想被实例化。与之相对的就是具象类

但是一般来說,抽象类还是有一些功能(属性方法)的。我们继续简化(抽象化)直到只剩下公开的抽象操作,而没有了属性和方法这种状态UML囿一个专门的名字:接口(interface)。

接口用来定义一组公共的特性和服务是服务提供者和利用者之间的协议,定义接口的目的就是为了替换甴不同的服务提供者提供的实现;抽象类抽取了具象类的共通特性并通过具象类实现完整的功能。目的在于抽取共通而不是定义行为②者的使用场景有很大的不同。

具象类到抽象类的关系叫泛化接口的实现到接口的关系就叫实现(realization)

在类图中接口和类的表示基本┅致,只是在类名上多了一个《interface》关键字实现则有两种表现形式:一是指向接口类的顶端带有三角形的虚线;另一种方式是带有《interface》关鍵字的依赖箭头。


更多更新文章欢迎关注微信公众号:【面向对象思考】


搜一下:软件工程硕士UML建模

用EA工具创作一个Actuator-Sensor模式的顺序图并配文字解释

你对这个回答的评价是

我要回帖

更多关于 软件工程硕士 的文章

 

随机推荐