使用模型驱动的方法和 UML 2.0 及 Ada 2005 接口来开发更灵活的 Ada 应用程序

转自

http://www.ibm.com/developerworks/cn/rational/10/developingsmarteradaapplicationsusingmodeldrivenapproach/

 

引言

对象管理组(OMG)的统一建模语言 1.x(UML 1.x)的初始版本,源自于三种面向对象的方法(Booch,OMT 和 OOSE),并从建模语言设计、面向对象的编程以及结构化描述语言集成了一系列的最佳实践方式。UML 1.x 语言对于为类建模功能强大,这些关系包括面向对象的关系,例如联系、附属、组合、聚合与泛化。图 1 显示了使用类图来联系类的方式。


图 1. UML 1.0 中的类图
屏幕截图显示了 UML 1.0 类图

但是当您在构建大型的系统时,我们想要只关注于类在聚合度方面是如何联系的,以及是如何隔离的。尽管在 UML 1.x 中可以定义接口,但是,对于结构化的符号没有内在的建模支持,这些符号显示了一个系统是怎样分解为子系统,或者子系统在这样的集合里是如何联系的。


使用 UML 2.x 对大型系统建模

在开发最新的统一建模语言标准时,作出了最大的改进,UML 2.x ,用于为大型系统的建模提供支持。特别需要指出的是,UML 2.x 努力巩固系统之系统的概念,其中任意的系统都可以由一系列的子系统组成,而子系统又可进一步分解为它自己拥有的子系统。为了做到这一点,UML 2 引入了一个称为组合结构的新概念。在这种背景下,所谓的“结构”是相互联系元素的组合,这些元素代表了运行时实例协作以达到一些公共的目标(见于资源)。因此,一个结构化的类,就包含了其他的类。

类之中类的实例就是所谓的部件。例如在图 2 中, Builder1 是一个结构化的类,它由两个部件组成,一个是 Transmitter 类的实例与一个 Receiver 类的实例。类可以由那些拥有部件的类组成,允许您按照层级结构将一个系统逐步分解成任意的层次。


图 2. 提供的和需要的接口与行为端口
显示组合类的图

在 UML 2.x 中还引入了端口的概念,它代表了标识符(例如类与角色)实例与其环境之间的交流点,或者标识符实例与它所包含实例(例如它的部件)之间的交流点。与端口相联系的接口指定了端口上可能发生的交流的本质。

范例显示了 Transmitter 与 Receiver 通过端口来联系。Receiver 拥有一个行为端口去处理访问。在一个行为端口上接口提供的具体操作由拥有端口类的实例来执行。图 3 显示了通过端口间连接器调用 Receiver 上异步信息的 Transmitter 。对于 Receiver 类来说,它简单地打印了对操控台窗口接受的字符。


图 3. 运行 Builder1 作为程序的屏幕截图
Tx 与 Rx 字符文本操控台


使用端口提供的和需要的接口

在 UML 中一个标识符(例如一个类或者角色)可以拥有任意数量的端口。每一个端口都需要根据其标识符来得到独一无二的名字。可以使用棒棒糖和插座符号通过一个端口来获得提供的操作与需要的操作。

  • “需要的接口”描述了标识符对其环境通过端口发出的请求。它用插座来标示(有时也称为一个杯)。
  • “提供的接口”描述了其环境通过端口对标识符的请求。它用棒棒糖来标示(有时也称为一个球)。

在面临需要的接口时,可以通过激活对其端口的服务,来设计和实施类。因为这样的端口在概念上解除了对提供者提供的类的耦合。

更为重要的是,可以使用具体的实现了相同接口的实施方案。这就使得端口对于基于构件的设计功能十分强大。因此使用端口可以轻松地将构件从一个集合转移到另一个集合中去。这意味着构件可以在不同的背景下使用,或者在完全不同的系统中使用。

例如,在图 4 中,Transmitter 完全没变,但是 Receiver 类却被 Banner 类提供,该 Banner 类提供了相同的接口,而且是 IReceiver 接口的完全不同的实施方案。


图 4. 非行为(中转)端口
显示组合类的图

该图还演示了非行为端口的概念。Banner 类没有提供 IReceiver 接口的具体实现方案;但是它中转其端口对内部构件的激活。非行为端口就是中转端口或者授权端口,它们向内部构件发送访问。

该图还展示了使用符号来“插入与运行”拥有相同接口的不同构件是多么的轻松。运行 Builder2 的输出显示在图 5 中。它演示了“itsBanner”部分是怎样将它接受的字符,以 滚动的标题形式基于像素的字母显示出来,而不是简单地将它们打印出来。重要的是,您可以更改类的实施方案,该类提供了 IReceiver 接口,而不用影响使用其服务的 Transmitter 类,图中还演示了在使用端口时“插入和运行”构件是多么的容易。


图 5. 运行 Builder2 作为程序的屏幕截图
显示带有文本的操控台窗口

一个给定的端口可以协调以提供任意给定数量提供的或者需要的接口,而一个标识符可能会有任意数量命名的端口。对于前沿性的 UML 工具,例如 IBM Rational® Rhapsody® 方案中存在的问题,在于怎样将 UML 中的构造合成为一个目标语言执行方案。


在 Ada 中表达一个面向对象的设计

在研究映射到端口之前,您必须先要理解 Ada 与 UML 之间的关系。当您在使用这些语言的单独环境中开发软件时,面向对象的设计中类与接口的关键概念,映射到 Ada 语言构造,是我们最大的关注点。

类是面向对象设计的构建模块,并定义了一系列对象的描述,这些对象共享了相同的属性、操作、关系与语义(见于图 2)。类的概念并不是 Ada 语言原创的。它通常使用 Ada 记录来合成以定义类的属性,并使用 Ada 包来定义可以调用该类型对象的操作 ,它是通过将一次处理作为操作访问的首个参数传递给记录来完成的。

接口的概念在 UML 中也很重要。所谓的 UML 接口定义为用于指定类或者构件服务的一系列操作。一个接口通常由不止一个的服务签名组成。通过在 UML 中说明一个接口,您可以在一个抽象的签名中来声明需要的行为,这种抽象的签名独立于具体的实施方案之外。接口是组成一个大型系统的一个重要方面,因为您可以使用接口来定义某个子系统“提供的”或者“需要的”操作的公共视图。

使用 Ada 95 语言,就可以使用 Ada 包与抽象的 null 记录类型来合成接口了,其中 Ada 包用于分组那些可以操作特定类型对象的子程序。Ada 95 存在的问题在于,它只支持一个获得的类型拥有即时的起源。因为记录类型用作对象操作激活的基础,所以这意味着某个类(或者组合类)给定端口上“需要的”或者“提供的”接口的数量只限于一,意味着不允许一个端口上存在多个接口。

本文向您展示了 Ada 2005 是怎样提高 Ada 开发团队的能力,以尽量使用高级的 UML 2.x 技术,以前使用像 C++ 和 Java 之类执行语言的开发员从这项技术中受益匪浅。Ada 2005 接口与 UML 接口之间协同支持的一个关键 UML 2 概念。这项端口支持组合结构的定义,这种结构中清晰但是抽象的接口,定义了“提供的”服务,或者客户所“需要的”服务。


利用 Ada 2005 接口

在 Ada 2005 中,引入了一个新的保留词 接口 来解决单次继承性的限制问题。Ada 2005 中的所有接口类型是绝对标记的类型。它们支持运行时调度(见于 图 3. 错误:没有发现引用源)。不像抽象的类型一样,接口不能宣布构件或者数据;它是用于定义可以激活子程序的签名的基础。因为 Ada 2005 中这样的接口只允许有抽象的子程序以及 null 程序作为操作。

下面的图 6 显示了两个接口。如果某项操作被宣布为 抽象的 那么继承的类必须提供了一个具体的实施方案。如果某个操作宣布为带有 null 关键词,那么继承的类就可以选择忽略 null 程序。


清单 1. 抽象的子程序与 Ada 2005 中的 null 程序

   package ILetter is

   type ILetter_t is interface;

   procedure Refresh (this : in out ILetter_t) is abstract;
   procedure Setup (this : in out ILetter_t; The_Char : in Character) is abstract;

end ILetter;

package IPrint is

   type IPrint_t is interface;

   procedure Print(This: in out IPrint_t, The_String : in String) is null;

end IPrint;

在 Ada 95 中,一个抽象的类型只能拥有一个即时的起源,但是在 Ada 2005 中,可能会从标记类型的多种接口中获得一个新的类型。您可以引用首个类型作为它的父类,并将其他的作为起源 。


图 7. 使用接口的多个接口

with ILetter;
with IPrint;

package Banner_Letter is

   type Receiver_t is new ILetter.ILetter_t and IPrint.IPrint_t with private;

   procedure Refresh (this : in out Receiver_t);
   procedure Setup (this : in out Receiver_t; The_Char : in Character);
   procedure Print(This: in out Receiver_t, The_String : in String);

private

   (hidden attributes)

end Banner_Letter;
        

定义接口的能力意味着访问者抽象于操作的具体实施操作以外。在图 8 中,类图显示了 Screen 拥有一列的零或者更多的 ILetter 对象。在这个例子中,Screen 类通过 ILetter 接口来激活操作,通过一系列的 ILetters 来进行迭代。对接口的访问会导致实时分配给 Banner_Letter 类提供的具体实施方案。使用这种抽象模式,Screen 就可以使用 ILetter 的不同实施方案了,假设它实现了 ILetter 接口操作的签名。


清单 2. 接口的使用与实现
类图与实现的接口

端口的代码工作模式很相似。如果是行为的端口,那么对提供的操作所做的访问是由拥有该端口的类处理的。这意味着拥有的类“实现”了端口上提供的接口。当有客户调用了一个行为端口上的抽象操作时,那么访问就会分配给该类了。


接线代码的自动化合成

在一个非行为的端口上,当客户调用一个抽象操作时,您需要响应对类的请求,该类实现了提供的接口。

关键之处在于,该端口接线代码是规则的,并且可以基于在组合结构图上定义的链接来自动生成。这意味着用户并不需要编写任何附加性的代码,他们可以使用图像化的符号来将某个部件置于给定的背景下,而代码生成员则可以基于定义的规则集来合成接线代码。例如,使用 Rational Rhapsody 环境,您就可以定义您想要构建一个 Builder2 组合类,而它以自动生成的模式来集合并实现了所有需要的部件,以及发送部件之间信息所需要的接线代码。

这就极大地简化了集成过程,并使得开发员可以使用图像化的 UML 2.x 概念来轻松“插入和运行”构件,以定义它们联系的方式。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14780873/viewspace-664881/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/14780873/viewspace-664881/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值