- 论坛徽章:
- 0
|
数据库系统在面向对象分析设计中的应用(转)
数据库系统在面向对象分析设计中的应用(四)
作者 3871
转载自网易虚拟社区 http://club.netease.com
1、 整体-部分结构
先举个例子:一个公司客户有多个联系人,"客户"类与"联系人"类是整体-部分结构。
联系人的数目有限时,可以直接用嵌入的方法将联系人嵌入到客户中,或用指针方法在程序中实例化出来。当联系人的数目达到相当数量时,必须考虑这些联系人的增加、删除、修改等管理功能。
于是,应该在客户的模型(类)中,建立一个"联系人列表"属性,将已经实例化的联系人资料(属性)永久保留下来。"联系人列表"是"联系通讯录"类的一个实例。
如前所述,"联系人通讯录"是一个基于数据库操作的类。其内部有一个对应数据库的表,在此表上建立增加、删除、修改的服务。最重要的,用"取出"服务及录入、修改对应对象数据库属性的方法实现对象与数据库间的保存与恢复。
所以,在对"联系人"这一数据库进行设计时,必须设计一个"客户"(或客户编号)字段,描述这一联系人所从属的客户。当从"联系人通讯录"类中实例化出"联系人列表"时,就从联系人数据库中根据客户编号 SELECT出联系人,这些联系人集合,就是该客户已经实例化所有联系人的集合。
2、 一般-特殊结构
这是我们讨论的重点。为了更好地解释我的方法,先假定有一个这样的系统:系统中有一个"人员"类,其模型是这样的:
属性:姓名、性别
服务:为便于理解,暂无
系统中还设计了"员工"模型与"联系人"模型,它们都从"人员"中继承而来,除了"人员"中所有的属性与服务外,特殊化的属性与服务是:
员工:属性:籍贯、身份证、出差状态
服务:出差
联系人:属性:所在单位、电话、手机
服务:报价
联系人类又有一个子类,子类名为"区域联系人",与联系人类不同的是,有一个叫"所在区域"的属性,其模型为:
区域联系人:属性:所在区域
服务:暂无
显然,员工、联系人、区域联系人的实例化对象达到一定数量时,必须管理这些已实体化对象。为简化描述,只对联系人、区域联系人的已实体化对象建模,叫"联系人通讯录"、"区域联系人通讯录"
类之间的关系图如:
Sorry,贴不上图,是各对象间的特征-关系图。即分析的重要结果之一。
现在以上面的模拟系统为例,解释本文解决数据库实现继承关系的策略:
★ 将父类的属性组装到子类中实现继承
将一般-特殊结构与整体-部分结构是实现"一些对象可以拥有另外一些对象的特性"的两种方式的理论推而广之,将父类的属性组装到子类中是有理论根据的。
在面向对象的分析与设计中,分析与设计是主要的,数据库仅是实现永久属性保存的一种辅助。因此,在分析阶段,该用继承的概念还是继承,无需转化为数据库可以实现的整体-部分关系。在数据库的设计阶段,将具有继承关系的、而又需要永久保留的属性考虑用组装的方法。
在分析时,"联系人"继承"人员"的特征,这种描述显然比"联系人"有"人员"的特性这一描述准确、自然得多,因此,分析时,"联系人"与"人员"仍是继承关系,但在数据库设计量,可将人员的属性组装在"联系人"的属性
中,共同形成"联系人"数据库数据库结构。
组装父类、子类属性的方法可以分为紧密组装与连接组装。
紧密组装,是指父类的属性直接与子类的属性组装在一起,共同形成子类的数据库结构。连接组装指的是父类的属性与子类的属性并不在同一个实际数据库中,它们各自所在的数据库通过某个字段相联系,就如数据库理论中常见的Master-Detial结构一样。
"联系人"与"人员"数据库显然可以紧密组装"人员"的属性。但考虑这样一个从联系人中派生出来的类"区域联系人",这个类除了联系人所有的特性外,还有一个"所在区域"属性,而且很有可能某个区域联系人是在系统中某个已经实例化了的"联系人",这个时候,要用连接组装。
考虑紧密组装还是连接组装可以依据下面的原则:
A、 父类的抽象程度
父类的抽象程度越大(离现实生活越远),考虑紧密组装的可能性就越大。如"人员"这一比较抽象的概念,其子类"联系人"的数据库设计应该考虑的是紧密组装。
B、 要组装的父类的属性数量
如果经过仔细地审查,只有一两个属性的父类仍然有存在的必要,那么,完全可以考虑在数据库设计时将全部的父类属性组装到子类中。――因为现在的数据库技术与存贮容量,完全有能力承受。
C、 父类的已有对象实体是否已用数据库管理
如果父类的已有对象实体已经用数据库管理,尤其是子类的对象实体可能是父类已有实体的某些特性扩充时,显然子类与父类间应该用连接组装。正如"区域联系人"与"联系人",为区域联系人再建一个与联系人数据库的数据结构几乎一样的数据库显然是不合理的,更何况其中可能出现某区域联系人实体实际上就是联系人的某个实体的情况。
按照连接组装的概念,在数据库设计时,除了要在子类的属性数据库中有对象实体的唯一标识字段外,还要有标定该对象实体与父类属性数据库中相应对象实体相连接的字段。"区域联系人"的属性数据库结构(字段)应该是这样:
区域联系人编号
(父类)联系人编号
所在区域
下面再来讨论讨论对象的恢复问题。在子类的"取出"服务中,首先实例化出一个子类空对象(所有属性值均为初始值的对象),此时,这一实例化的子类空对象,已经从父类中继承了所有的属性。
对于紧密组装,由于父类与子类的属性值全部都紧密地组装在一个数据库中,将数据库中相应对象的各字段的值赋予子类可能拥有的所有属性即可。这里所说的"可能拥有的所有属性",包括了从父类继承过程的属性,从而最终返回这一具有实际意义的对象实体。
对于连接组装,由于子类数据库中只有相对父类特殊的属性,所以除了从子类属性的保存数据库中取出子类的特殊属性值外,还要用连接找到父类对应的属性保存数据库,取出其属性值,给这一实例中的相应属性赋值。
这样,一个包括全部父类、子类的属性的对象就产生了。
当"取出"服务根据属性所在的类,实例化出一个对象时,这个空对象已经具有了该类所有的一切服务,包括从父类中继承的所有服务。当这个类所有的属性值(包括从父类中继承的)赋值完成后,一个可跨越系统的运行期而存在的、系统中曾经实例化的已有的对象实体就被完完整整地还原出来了。组装连接可以解决多重继承的关系。对于组装连接,"联系人通讯录"与"区域联系人通讯录"没有任何属性方面的直接连接,一方面,使各自的对象可以封装得更好,另一方面,也产生了新的问题,考虑这样的一种情况:在"区域联系人"的"增加"服务中,由于"区域联系人"的对象实体数据库除了"所在区域"属性外,"姓名"等都 在"联系人"对象实体数据库中,是否先调用"联系人"的"增加"服务(画面),完了后再录入这个"所在区域"呢?这个方法的实际操作将是:一个画面录入联系人的资料,关闭这个画面后再录入唯一的一个资料"所在区域",显然,这是极不合理的。
将这种情况推而广之:怎样解决在组装连接中,修改(无论是录入性修改还是程序触发性修改)子类中从父类继承下来的、已经永久保留的属性。这就是下面所要论述的:
待续....
(一)、(二)、(三)、(四)、(五)
※ 来源:.网易虚拟社区 http://club.netease.com |
|