今天,本站带领大家来熟悉一下UML中的组件图。
组件图(Component Diagram)又称构件图,是UML中描述一个系统中的物理方面的图形,它是用来描述构成系统的各个组件、组件提供的接口与需求的接口、端口以及它们之间关系的图。
这种图在基于组件开发的系统建模中很重要。
组件图可以帮助用户理解系统的结构。
组件图中主要包括组件、接口及其它们之间的关系三种元素。
组件(Component)是定义了良好接口的、可重用的、可替代的物理实现单元,它一般表示实际存在的、物理的物件。
程序源代码、可执行文件、子系统、一个脚本、动态链接库(DLL)、ActiveX控件都可以成为系统中的组件。
组件隐藏了内部实现的细节,仅通过接口提供服务。
我们可以把组件理解为一个黑盒子,这个黑盒子使用接口来公开其公共可见的属性及操作,这一点与类非常相似。
在UML1.x版本中,一个标准的组件使用如下的图形来表示。
而在UML2.x中一般使用如下的图形来表示一个组件。
也可以使用类似类的矩形框加上构造型<<component>>来表示组件,如下图所示:
组件中的接口主要分为两类:提供接口(Provided Interface)和需求接口(Required Interface)。
提供接口又称导出接口,是组件提供的服务的集合。
提供接口是由组件本身直接实现的接口、或者是由实现组件的类之一实现的接口,或者是由组件的公共端口提供的接口。
提供接口可以使用接口与组件之间的实现关系来表示。
提供接口可以在组件图标的边框上使用类似棒棒糖式(lollipop)的图标来表示。如下图所示:
这个图表示WeatherServices组件提供或实现了WeatherForecast接口。
它可以认为是下图的简化表示方法:
需求接口又称导入接口,是组件请求其它组件相应服务时遵循的接口。
需求接口通过依赖关系来表示,需求接口可以使用插座(Socket)的图标连接到组件边框上来表示,如下图所示:
上面这个图表示UserServices组件需要(依赖)IOrderServices接口。
它可以认为是下图的简化表示方法:
作为一种可选方式,可以把组件的接口或组件的操作和属性列在组件图标下边的隔室里。
上面这个图表示,UserServices接口提供的接口有IUserServices,需求的接口有IOrderServices。
端口用于描述组件或类与它的环境、与其它类、与其它组件或内部部件的交互点。这个交互点一般是组件或类的一个属性,默认情况下,端口具有公共可见性。
端口使用类或组件边框上的一个小矩形来表示,如下图所示:
上图表示BorrowServices组件有一个borrowPort端口。
接口通过端口来提供服务或获得服务,下图表示了这种情况:
组件图中的关系主要包括两种:依赖关系和实现关系。
组件图中的依赖关系与类图中相同,都是“供应者-客户”关系(supplier-client),使用虚线箭头由客户(client)组件指向供应者(supplier)组件。
下图表示组件“borrowBook”依赖于组件“Book”,其中,“borrowBook”是客户组件,Book是供应者组件。
下图也表示了两个组件之间的依赖关系,它表示了borrowBook组件的一个需求接口依赖于Book组件的一个提供接口:
一般这种依赖关系都是从插座接口引出指向棒棒糖接口。
上图也可以简化成下面的形式:
上面这个图表示了borrowBook使用某个需求接口与Book组件的提供接口产生依赖关系。
这种图在UML2.x中被定义为连接。
组件之间的实现关系表示一个组件实现了另外一个组件。这与类和接口之间的实现关系相同。
下面第一个图表示组件borrowBook实现了组件IBorrowBook。
如果IBorrowBook组件仅包含一个接口的话,也可以使用第二个图来表示(见上面关于组件提供接口的说明)。
组件实现了一个接口意味着组件支持接口中的所有操作。
Scott W.Ambler在其著作《The Object Primer:Agile Model-Driven Development with UML 2.0》第三版中给出了关于组件建模技术的一些方法和技巧:
在实际组件建模中可以采用自顶向下的方法,也可以使用自底向上的方法。
使用自顶向下的建模方法可以使设计人员能够更清晰的了解软件的未来架构,但这种方法容易导致系统的过度架构化,从而导致系统的过度建模,易使设计人员过度关注细节,而忽略了客户的真正需求。
使用自底而上的方法可以在类建模的基础上把已设计的类进行组件化,把系统中可重用的部分分离出来,或者将应用程序进行拆分,以便把任务轻松地分配给相应的团队。
在组件建模中可以使用如下步骤或原则进行建模:
(1)保持组件的内聚性
一个组件应保持其功能单一性或功能相关性。如,一个组件仅包含某类用户的用户界面、或者仅包含大规模领域概念的业务类,或者仅包含公共基础概念的技术类。
(2)将用户界面类分配给应用程序组件
用户界面类,如页面、报告以及实现相关逻辑的类,应该放在带有“application”构造型的组件中。如Java中JSP页面、servlet和Swing类等。
(3)把技术类分配到基础架构组件中
实现系统级服务的类,如安全、持久性或中间件,应该分配到带有“infrastructure”构造型的组件中。
(4)定义类的契约
类契约是指能够直接响应其它对象发送的消息的方法(操作)。
如在Books类中很可能包括getBookInfo()这样的方法,这样的方法能够响应来自其它组件中对象发送的消息。
为了很好的识别组件,你可以忽略所有非类契约的操作,原因是这些操作对促进分布在不同组件中的对象之间进行通信不会提供太大帮助。
(5)把一个具有层次结构的所有类(如类的继承或聚合层次结构)分配到相同组件中。
(6)识别领域组件
若干类相互协作以完成特定的任务,这些类满足内聚要求,从而成为一个领域组件。其它类或组件能够通过向该领域组件发送消息以请求获得信息或执行操作。领域组件对外显示出其简单性,但其内部通常很复杂。领域组件设计的目标是减少网络通信,而使大多数信息流发生在其内部。
(7)确定业务类的协作类型
服务器类是接收消息但不发送消息的类;客户类是发送消息但不接收消息的类;客户/服务类是兼有发送消息和接收消息的类;在确定好每个类的分布类型后,就可以开始确定潜在的领域组件了。
(8)把服务器类归为一个组件中
纯服务器类属于领域组件,他们是应用程序中消息流的“最后一站”。
(9)将仅为某客户端类服务的组件合并到其客户组件中
如果一个领域组件仅为某一个组件提供服务,那么可以把这两个组件合并为一个组件。
(10)单纯的客户端类不应归到领域组件中
客户端类只生成消息而不接收消息,不应属于领域组件。领域组件的目的是响应消息。客户端类很可能属于应用程序组件。
(11)高度耦合的类应归为一个组件中
两个频繁协作的类应位于相同的领域组件,以减少两个类之间的网络流。即,高度耦合的类应放在一起。
(12)遵循最小化组件间的消息流原则
在确定一个客户类/服务类属于哪个组件时,要充分考虑流入和流出类的信息流。组件内的通信通常是在内存中对象之间简单的消息发送。组件间的通信往往需要消息的转换、传输等额外的支出。
(13)定义组件的契约
每个组件应向客户提供服务,这样的服务即为组件的契约。
Rational Rose支持1.x的组件图绘制方法,其能表示组件与接口之间的实现关系以及组件之间的依赖关系,但不能绘制“Socket”插座式的需求接口形式。用户在实际中可以通过接口之间的依赖来表达。
在Rose中,在组件视图(Component View)中创建组件图,可以在Rose中左侧的浏览器中的“Component View”上右击,然后选择“New”->“Component Diagram”。
使用组件图创建工具栏中的“组件”可以创建一个组件。
组件图中的工具箱如下图所示:
选“组件”工具后,在绘图区点击一下即可以完成一个组件的创建。
(1)用户在创建组件时,可以直接修改组件的名称;
(2)在左侧浏览器中,选中要修改名称的组件,然后右击后选择“Rename”,最后,输入新的名称即可,具体如下图所示:
(3)在绘图区中,在对应的组件上右击后,在弹出的快捷菜单中选择“Open Standard Specification...”。
这个操作会打开如下图所示的对话框:
在这个对话框的“Name”中可以输入新的组件名称。
在Rose中,要彻底删除一个组件,可以通过以下几种方式:
(1)在绘图区中,右击要删除的组件,在弹出的快捷菜单中选择“Edit”->“Delete from Model”菜单项;
(2)选中要删除的组件,按下“Ctrl+D”组合键,则可以快速删除组件;
(3)选中要删除的组件,选择菜单栏中的“Edit”->“Delete from Model”菜单项;
(4)在左侧浏览器中,在要删除的组件上右击后,在弹出的菜单中选择“Delete”。
以上的四种操作方法,将会把组件在所有模型中彻底删除。
如果其它模型中使用了该组件,且只是把组件从当前模型中的话,用户可以选中组件后,直接按下键盘中的“Delete”键即可,或者右击要删除的组件后,在快捷菜单中选择“Edit”->“Delete”也可以实现该操作。
在Rose中,可以为组件指定其要实现的接口(提供接口——Provided Interface),具体操作方法如下:
(1)右击要设置的组件,在弹出的快捷菜单中选择“Open Standard Specification...”;
(2)在弹出的对话框中选择“Realizes”选项卡,该选项卡中列出了模型中所有的类和接口,具体情形如下图所示:
(3)在要实现的接口上右击后,选择“Assign”(分配)菜单项。
操作情形如下图所示:
分配完接口后的组件及操作对话框后的情形如下图所示:
我们可以看到,组件上多了两个接口(提供接口),同时在“Realizes”列表中,以分配到该组件的接口上将出现红色的“√”符号。
为组件指定实现的接口后的样子如下图所示:
它表示IBook和IReader接口在组件BorrowBooks中实现的,也表示BorrowBooks提供了IBook和IReader两个接口(提供接口)。
如果用户想把一个接口从组件中移除,用户可以在列表中的组件上右击后,在弹出的菜单中选择“Remove Assignment”菜单项。
实际上,以上操作相当于定义了组件和接口之间的实现关系。
用户也可以使用同样的方法,把组件中包含的类分配到某个组件中。
(4)添加依赖关系
组件图中的依赖关系需要借助工具栏中的“依赖”工具来实现。
具体操作办法如下:
①用户点击“依赖”工具;
②在依赖元素上点击后,一直按住鼠标左键,拖动鼠标到被依赖元素上松开鼠标左键,则完成了元素之间的依赖关系。
如下图显示了组件“Fine”和接口“IFineRecords”之间的依赖关系。
它相当于组件的需求接口(Required Interface)。
Visio中虽然提供了一些绘制UML图的模板,但没有提供专门绘制组件图的模板。但用户可以在Pavel Hruby博士的网站上下载专门用于绘制UML图的Visio模具包。
这个Visio模具包叫“Visio Stencil for UML”。
该模板可以支持UML2.5中的各种图形,包括用例图、类图、时序图、包图、状态机图、组件图等。
你可以在微信搜索“优雅的代码”订阅号,关注后,消息中回复“visio uml”关键字来获取该模板的下载地址。
下载后,把这个模具包解压缩到你的电脑某个磁盘中的某个目录中以备使用。
Visio Stencil for UML针对不同的Visio版本有不同的模具。正常情况下高版本的Visio可以支持低版本的Visio Stencil for UML。
(1)打开Visio,新建绘图;
(2)选择“更多形状”,然后选择“打开模具”;
(3)选择你解压缩后的Visio Stencil for UML模具。
这样,就可以把下载的模具加载到绘图区中来了。
你也可以把下载解压缩的文件放到Visio默认的模具路径中,具体操作方法为:
在“文件”菜单中选择“选项”,然后在左侧选择“保存”项,在右侧列出的内容中找到“默认个人模板位置”,这里是模板保存的路径,你可以把解压缩后的Visio Stencil for UML文件复制到这个文件夹中。
或者你在这里直接输入Visio Stencil for UML所在的路径。
下图显示了这个工具中提供的绘制UML图的全部图形符号。
同时,在下载的工具中也提供了一些UML其它的构造型符号供设计时使用。
(1)添加一个组件
在左侧形状中,选择“Component”(组件),然后把它拖曳到绘图区中来。
(2)输入名称
双击组件符号,输入或修改组件的名称。
(3)调整组件显示大小
如果需要调整组件的大小,可以选中组件,在其周围会出现若干个白色的小方块,如下图所示:
鼠标到上面会变成双向箭头的形状,然后按住鼠标左键,通过拖拽来改变图形的显示大小。
(4)修改字体
选中组件后,在“开始”功能区的“字体”分组中可以修改字体、颜色以及字体的大小、是否加粗、是否有下划线等设置,如下图所示:
在左侧形状中选择“Interface,Socket”图形,如下图所示的图形:
然后把它拖曳到绘图区中的组件附近,这时,相应的组件周围会出现若干贴附点,如下图所示:
选择一个贴附点,然后松开鼠标后,其会变成如下的形式:
用户可以选中接口,通过按住圈中(接口)的黄色小方框来拉长接口的线。
默认是提供接口(Provided Interface)的形状,如果想要添加需求接口(Required Interface),则只需在添加的接口上右击,然后选择“Socket”即可,如下图所示:
则原来的提供接口的形状就变成了需求接口的形状,如下图所示:
在这个工具中可以通过在绘图中添加“Straight Relationship”为组件图中添加依赖关系。
然后将其微端连接到依赖元素的贴附点上,其头端连接到被依赖元素的贴附点上。
默认添加的“Straight Relationship”为一条直线,情形如下图所示:
用户可以通过右击这个直线,然后在菜单列表中选择“Dependency”,即完成依赖关系的绘制。
下图是修改完联系类型的情形:
下面是图书馆借阅系统中的组件图,这个组件图即是使用上面介绍的Visio Stencil for UML工具创建而成的。
下图是在Rose中实现的例子:
新闻热点
疑难解答