指南:对关系数据库实施逆向工程
指南:对关系数据库实施逆向工程主题要从关系数据库方案中生成对象模型,可执行下列步骤。 在设计模型中复制 RDBMS 表
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 列名 | 数据类型 |
| Customer_ID | Number |
| Name | Varchar |
| Street | Varchar |
| City | Varchar |
| State/Province | Char(2) |
| Zip/Postal Code | Varchar |
| Country | Varchar |
表 Customer 的表定义
根据以上表定义,我们将创建类 Customer(客户),其结构如下图所示:

初始 Customer 类
在这一初始 Customer 类中,对于 Customer 表中的每一列都有一个属性。由于可以查询源表中的所有列,每个属性都具有公有可见性。
请注意,属性左侧所列的
图标表示该属性是“公有”的;默认情况下,所有从 RDBMS 表中派生的属性都应是公有的,因为 RDBMS 通常允许对所有列进行不受限制的查询。
确定是嵌入类还是隐含类 ![返回页首]()
表到类的直接映射所产生的类通常包含有可分离成一个单独类的属性,尤其是当属性在大量的转换所得类中出现时。之所以会产生这些“重复属性”,可能是由于为改善性能而对表进行的非常规化,也可能因为数据模型过分简化。在这些情况下,可以将相应的类拆分为两个或更多的类,以显示表的常规化视图。
示例
在定义上述的 Customer 类之后,我们几乎可以立即定义一个包含所有地址信息的 Address(地址)类(假定我们的系统中将有其他带地址的对象),于是就得到以下类:

修订过的 Customer 类和抽取出的 Address 类
由于客户的地址可以被看作是客户的一部分,所以这两个类之间的关联关系是聚合关系。
处理外键关系 ![返回页首]()
对于表中的每个外键关系,都要创建一个关联类之间的关联关系,并从类中删除与外键列对应的属性。如果外键列最初被表示为属性,则从类中将其删除。
示例
假定表 Order 的结构如下所示:
| 列名 | 数据类型 |
| Number | Number |
| Customer_ID | Varchar |
表 Order 的结构
在以上列出的表 Order 中,列 Customer_ID 是一个外键引用,该列包含与 Order 相关联的 Customer 的主键值。在设计模型中,我们将这种关系表示如下:

外键关系在设计模型中的表示
外键被表示为类 Order(订单)与类 Customer 之间的关联关系。
处理多对多关系 ![返回页首]()
RDBMS 数据模型使用所谓的联接表或关联关系表来表示多对多关系。这些表使多对多关系可以通过一个中间表来表示,该中间表包含可能联接在一起的两个不同表的主键。之所以要使用联接表,是因为一个外键引用只能包含对单个外键值的引用;当单个行可能与另一个表中的多个其他行相关时,就需要用联接表使它们相关联。
示例
请考虑产品这一情况:产品可以由众多供应商中的任何一个来提供,并且任何供应商都可以提供任何数量的产品。表 Product 和表 Supplier 的结构定义如下:
| Product 表 | Supplier 表 | ||||
| 列名 | 数据类型 | 列名 | 数据类型 | ||
| Product_ID | Number | Supplier_ID | Number | ||
| Name | Varchar | Name | Varchar | ||
| Description | Varchar | Street | Varchar | ||
| Price | Number | City | Varchar | ||
| State/Province | Char(2) | ||||
| Zip/Postal Code | Varchar | ||||
| Country | Varchar |
表 Product 和 Supplier 的表定义
为了将这两个表链接到一起,以查找由特定供应商提供的产品,我们需要一个 Product-Supplier 表,其定义如下表所示。
| Product-Supplier 表 | |
| 列名 | 数据类型 |
| Product_ID | Number |
| Supplier_ID | Number |
Product-Supplier 表定义
此联接表中包含产品 (Product) 和供应商 (Supplier) 的主键,从而将表 Product 和 Supplier 链接了起来。联接表中的一行将显示一个特定供应商提供一种特定产品。对于所有与特定供应商 ID 匹配的 Supplier_ID 列,它们所在的行都会提供由该供应商提供的所有产品的列表。
在设计模型中,此中间表是多余的,因为一个对象模型就可以直接表示多对多关联关系。Supplier 类和 Product 类以及它们的关系与 Address 类一起显示在图 8 中,Address 类是按照前面的讨论从 Supplier 中抽取的。

Product 类和 Supplier 类的表示
引入泛化关系 ![返回页首]()
通常,您会发现有些表具有某种相似结构。关系数据模型中没有泛化关系的概念,因此无法表示两个或更多个表在结构上的共同之处。有时,共同结构是为改善性能而进行的非常规化所产生的,上述的“隐含”Address 表(我们将它抽取到一个单独的类中)就属于这种情况。在其他情况下,各个表都具有更多共同的基本特点,我们可以将这些特点抽取到一个具有两个或更多子类的泛化关系父类中。为了寻找泛化关系的机会,需要在若干个表(其相似之处多于不同之处)中查找重复的列。
示例
请考虑下面的两个表:SoftwareProduct 和 HardwareProduct:
| SoftwareProduct 表 | HardwareProduct 表 | |||
| 列名 | 数据类型 | 列名 | 数据类型 | |
| Product_ID | Number | Product_ID | Number | |
| Name | Varchar | Name | Varchar | |
| Description | Varchar | Description | Varchar | |
| Price | Number | Price | Number | |
| Version | Number | Assembly | Number |
SoftwareProduct 表和 HardwareProduct 表
请注意,用蓝色突出显示的列是相同的;这两个表的大部分定义都相同,它们只是略有不同。为了表示这种关系,我们可以抽取一个共同的 Product(产品)类,并将 SoftwareProduct(软件产品)和 HardwareProduct(硬件产品)当作 Product 的子类,如下图所示:

SoftwareProduct 类和 HardwareProduct 类,显示到 Product 类的泛化关系
下图将包括所有的类定义,以显示订单输入系统的综合类图(只有主要的类)

订单输入系统的综合类图
在设计模型中复制 RDBMS 行为 ![返回页首]()
由于关系数据库通常不是面向对象的,并且几乎与对象模型中的类操作没有任何相似之处,所以对行为进行复制较为困难。以下步骤有助于重新构建上面确定的类的行为:
- 创建操作以获取或设置每个属性。需要通过一种方法来设置、变更及查询对象属性的值。由于访问对象属性的唯一方法是通过类提供的操作,因而必须在类上定义这种操作。在创建用于设置属性值的操作时,务必要包括可以对关联关系列执行操作的所有确认约束。如果没有确认约束,您可以选择只表现如下事实:这些属性可以通过将属性标志为具有“公有”可见性来进行获取和设置,如以上各图所示(利用属性名左侧的图标)。
- 在类上为每个在关联关系表上操作的存储过程创建一个操作。存储过程是在 DBMS 自身内执行的可执行子过程。此逻辑需要转换为设计模型。如果某个存储过程只在一个类上操作,就要用与该存储过程相同的参数和返回类型在该类上创建一个操作。记录存储过程在操作中的行为,并务必要在方法说明中注明:此操作由该存储过程实施。
- 创建操作以管理类间的关联关系。如果两个类之间存在关联关系,就必须通过某种方法来创建、管理和删除关联关系。对象之间的关联关系通过对象引用来管理。因此,如果要创建 Order 和 LineItem 之间的关联关系(即,将 LineItem 添加到 Order 中),就会调用 Order 上的一个操作,并将 LineItem 作为实参传递(即 Order.add(aLineItem))。另外,还必须有删除和更新关联关系的方法(即 Order.remove(aLineItem) 和 Order.change(aLineItem,aNewLineItem))。
- 处理对象删除。如果目标语言支持显式删除,就要通过在类的析构函数中添加行为来实施引用完整性检查。如果数据库中有引用完整性约束(如 cascade delete),就需要在适当的类中复制行为。例如,数据库可以定义一个约束,以表明只要删除一个 Order,就应删除所有关联关系的 LineItems。如果目标语言支持垃圾收集,就要创建一种机制,以便在对相关对象进行垃圾收集时从表中删除行。请注意,这听起来困难,而实施起来会更困难:因为您需要实施一种机制来确保所有数据库对象都不会引用将进行垃圾收集的对象;只依赖于执行环境/虚拟机的垃圾收集功能是不够的,因为那只是一名客户眼中的世界。
- 处理查询所暗示的行为。请检查 Select 语句,这种语句通过访问表来查看信息的检索和处理方式。对于每个由 Select 语句直接返回的列,应将相关属性的 public(公有)特征设置为 true;其他所有属性都应是 private(私有)。对于 Select 语句中的每个计算所得列,都要在关联类上创建一个操作,以进行计算并返回值。在考虑 Select 语句时,还要包括嵌入在视图定义中的 Select 语句。
|
Rational Unified Process |
浙公网安备 33010602011771号