480 likes | 630 Views
第九章 联系的实现. 对象类型间通过属性的引用建立了对象实例间的联系 本章重点研究对象间联系的语义及其实现方法 对象间的联系可以是 n 元联系 (n ≥2 ) n 个对象间通过一个联系进行联接 其中最简单,常用的是二元联系 (n=2) 二元联系中,二个对象间的联系语义有 1:1 , 1:N , N:1 , N:M. Rbin. Tright. Tleft. §9.1 没有属性的二元联系. 一个二元联系本身没有任何属性,它只表达了二个对象类型间的联系 联系的实现:通过设置进入点 entry point 来完成
E N D
第九章 联系的实现 • 对象类型间通过属性的引用建立了对象实例间的联系 • 本章重点研究对象间联系的语义及其实现方法 • 对象间的联系可以是n元联系(n≥2) n个对象间通过一个联系进行联接 • 其中最简单,常用的是二元联系(n=2) • 二元联系中,二个对象间的联系语义有 1:1,1:N,N:1,N:M
Rbin Tright Tleft §9.1 没有属性的二元联系 • 一个二元联系本身没有任何属性,它只表达了二个对象类型间的联系 • 联系的实现:通过设置进入点entry point来完成 • 进入点设在Tleft处:Tleft类型增加一个引用对象Tright的属性,Tright类型无需增加属性 • 进入点设在Tright处 • 增加一个对象类型Rbin,它仅有二个元组属性,分别是Tleft类型和Tright类型,这种方法可以加载Rbin本身独特的属性
1:1的二元联系的实现 (一)无冗余的表达方式—一个联系仅在一个对象属性中表达 • 采用① (或者②)方法—应当从查询需求入手,选择查询频度高的一方作为进入点 —问题: 1)反向查询速度极慢:对一个特定的Tright实 例,查其相应的Tleft实例时需要查过所有的 Tleft实例集合 2)即使正向查询,若存在联系的偶对集合很 小,那么仍然费时
1 1 R Tright Tleft • 采用方法③—定义一个Rbin类型,Tr并由系统维护Tr集合,适用于Tr相对Tleft(Tright)较小时 —问题: 1)需要二次查找才能定位 2)当Tr集合仍然庞大是,寻找一组特定的偶对效率仍然很低——需要建立索引 type Tleft is body [… R:Tright; …] end type Tleft; type Tright body [… R-1 :Tleft; …] end type Tright; type TR is with extension is body [left:Tleft; right:Tright;] end type TR;
1:1的二元联系的实现(续) (二)冗余的表达方式1——二个进入点 • 在Tleft中建立R属性—类型为Tright • 在Tright中建立R-1属性—类型为Tleft 优点:提高反向查询效率 问题:当两个对象实例间的联系发生变更时,容易产生修改异常,生成对象库状态的一致性受到破坏
解决方法:重新定义R属性的值接受操作 refine R:←Tright code setR; define setR(oright) is begin oright.R-1 := self; self.R := oright; end define setR; • 由此,确保了R属性与.R-1属性的同步修改 • 必须利用封装技术来控制不会单独修改.R-1 (.R-1只读)
总结 • 利用封装技术重新定义关联属性的状态的修改 • 特别注意不能在同一时间,以同样的方式修改类型Tright的.R-1的值接受操作,否则导致递归操作的无限循环 即: • 重写Tleft,R的值接受操作 • 隐藏Tright,.R-1的值接受操作,使其为只读类型
type Tright body [… R-1 :TR; …] end type Tright; type TR is with extension is body [left:Tleft; right:Tright;] end type TR; type Tleft is body [… R:TR; …] end type Tleft; (三)冗余表达方式2—采用显式的冗余方式 • 用TR作为中间联系方法将二者显式相连 • 查询为二次查询,但管理方便 • 对R, R-1的修改自然要遵照异常处理方式重定义VCO和做相应的隐藏
R Tleft Tright 1:N 的二元 联系的实现 1 N type Tleftis type Trightistype TR body body with extension is […… […… body R: { Tright }; R-1: Tleft; [left: Tleft ; ……] ……] right: Tright;] end type Tleft; end type Tright ; end type TR ; 方式(1) 方式(2) 方式(3)
其中唯有方式(2)能确保一致性约束,R-是单值的。其中唯有方式(2)能确保一致性约束,R-是单值的。 • 方式(1)(3)均不能确保两对象间1:N的约束。 • 对(1),必须重新定义R属性的值接受操作 • 对(3),必须对TR的对象实例库进行一致性维护,即TR的insert操作进行一致性维护
R Tleft Tright N:M的二元联系的实现 N M type Tleftistype Trightistype TR body body with extension is […… […… body R: {Tright }; R-1:{ Tleft }; [left: Tleft ; ……] ……] right: Tright;] end type Tleft; end type Tright;; end type TR; 方式(1) 方式(2) 方式(3) • 采用原则:以最大查询频率为依据选择入口点 • 可以采用组合冗余方法,但需要进行状态一致性维护
具有K个属性的二元联系的实现 ak a1 … • 1:1的联系:仍然可以采用方式(1)或(2),K个属性寄放在Tleft或Tright • 1:N的联系—只能放在单值属性的对象类型方 • N:M的联系—寄存在那一方均不合适,只能采用方式(3),定义此属性的类型TR, TR具有K+2个元组属性 Tright Tleft R
Type TR withextension is Body [left: Tleft ; right: Tright; a1:T1R; … ak:TkR;] operations declare TR: Tleft , Tright,T1R, …, TkR -> TR code initTR; implementation define initTR(Oleft ,Oright,O1,…,Ok) is begin self.left := Oleft; self.right := Oright; self.a1 := O1; …; self.ak := Ok ; enddefine initTR endtype TR
N—元联系的实现 • 只能采用方式(3)—建立TR类型处理 • 对初始化进行重定义,以保证约束的一致性。 • 为了检索高效率,需要考虑受控的冗余建模。 ak a1 … T1 Tn T2 R
type TR withextensionis Body [entitiy1: T1 ; … entitiyn: Tn; a1:T1R; … ak:TkR;] operations declare TR: T1 ,… , Tn,T1R, …, TkR -> TR … implementation … endtype TR
residesIn Engineers Offices 示例分析(一) • 1-1联系实例:工程师与他所占办公室的联系处理 约束条件:一个工程师一间办公室 type Engineer istype Office is bodybody […… […… resideIn: Office; isOccupied: Engineer; ……] ……] endtype Engineer ; endtype Office; 先有工程师,再分 经常查询某办公室的工程师是谁 配房间 1 1
用方式(1)和(2)组合建模下冗余的一致性维护 • 联系更新时一般的方式 (1)If (thePenthouse.isOccupiedby != NULL) thePenthouse.isOccupiedby.residesIn :=NULL; (2)If (leonardo.residesIn != NULL ) leonardo.residesIn. isOccupiedby :=NULL; (3) leonardo.residesIn := thePenthouse; (4) thePenthouseis.Occupiedby := leonardo;
设计操作moveToOffice来维护一致性状态 define moveToOffice(newResidence ) is begin if (newResidence.isOccupiedBy != NULL) newResidence.isOccupiedBy.residesIn := NULL; if (self.residesIn != NULL ) self.residesIn.isOccupiedBy := NULL; self.residesIn := newResidence; newResidence. isOccupiedBy := self; enddefine moveToOffice;
worksFor Engineers Divisions 示例分析(二) • 工程师与部门间的1:N的联系 type Engineer istype Division is bodybody […… […… worksfor: Division; employs: EngineerSet; ……] ……] endtype Engineer ; endtype Division; type EngineerSet is body {Engineer} endtype EngineerSet; N 1
控制类型冗余模型的两个操作 • hire define hire(newEng) is Begin self.employs.insert(newEng); newEng.worksFor := self; enddefine hire; • Fire define fire(badEng) is Begin self.employs.remove(badEng); badEng.worksFor := NULL; end define hire; • 聘用和辞退两个操作可以保持DB的完整性约束。
Sub N products composition 1 Super 递归的1:N的关系 • 产品与产品间具有递归的组合联系 • E-R图的展开可以有两种描述模式
A:通过Super属性—表达了is.part-of的语义关系: 即:一个产品属于上层产品的一个部件 type Product is body […… super: Product ; ……] endtype Product ; 适用范围:查找某种产品被组装在什么部件中。沿part-of路径进行导航或访问 Super: Super: Super: Super: Super: Super: Super: Super:
B:通过Sub属性—表达了partlist的语义关系: 即:一个部件由几个子部件所组成 type Product is body […… sub: ProductSet ; ……] endtype Product ; type ProductSet is body{ Product } end type ProductSet ; 适用范围:查找组成某部件的所有子部件 Sub:{} Sub:{} Sub:{} Sub:{} Sub:{} Sub:{} Sub:{} Sub:{}
应用示例 • 操作partlist:输出组成某个产品的所有部件 • 采用结构I define partList is var resultSet: ProductSet; begin resultSet.create; !!create an empty set resultSet.insert( self ); foreach ( part inext( Product )) if ( part.super = self ) resultSet.setUnion(part.partList); !!recursive call of partList return resultSet end define partList
采用结构II define partList is var resultSet: ProductSet; begin resultSet.create; resultSet.insert( self ); foreach (part inself.sub) resultSet.setUnion(part.partList); !!recursive call of partList return resultSet; end define partList; • 该程序是高效的。
操作is part of: • 采用结构I define isPartOf(theSuperPart) is !!is self a subpart of theSuperPart? var part: Product Begin part := self; while ( part != NULL ) If ( part = theSuperPart ) return true; else part := part.super; return false; end define isPartOf; • 高效,只需沿self向上查找到根一条路径
采用结构II define isPartOf(theSuperPart) is var isUsed: bool := false; Begin foreach ( part in theSuperPart.partList) If ( part = self ) isUsed := true; !!we could already exit the loop here return isUsed; end define isPartOf; • 低效,需到theSuperPart节点的所有组件中寻找self
第III种冗余组合模式 type product is body [… super:Product; sub:ProductSet; … ] end type product • 该模式的使用中,重要的是维护DB的一致性
designs Engineers Products N:M关系举例 N M • 方式一,采用组合的冗余表达方式 type Engineer istype Product is body body […… […… designs: ProductSet; designedBy: EngineerSet; ……] ……] end type Engineer ; end type Product; type EngineerSet istype ProductSet is body {Engineer} body {Product} end type EngineerSet; end type ProductSet;
方式二,采用单独定义的TR类型表示联系 type Designs with extension is body [theParticipatingEngineer:Engineer; theProduct:Product] end type Designs
互逆联系的实现 • 问题的提出:在用冗余表达对象间的联系时,如何用系统来自动维护修改的一致性? • 互逆联系:对称的联系偶对,由inverse显示标识。 • 系统将按照用户标识指定的互逆联系的修改进行自动的一致性维护。
(一)1:1的单值逆属性 • 示例:关于婚姻的一致性控制,没有两个类型及其冗余的联系: type Man is type Woman is body body [ [ … … wife:Woman husband:Man ... … ]; ]; end type Man; end type Woman
mickeyMouse.wife := miniMouse; miniMouse.husbnd:=donaldDuck; • 控制婚姻联系的一致性约束条件为: w.husband =m; 当且仅当 m.wife = w • 如果上面的约束由系统自动维护,则需要用户显示的指明互逆联系
type Man is … wife : Woman inverse Woman$husband; … end type Man; type Woman is … husband : Man inverse Man$wife; … end type Woman; mickeyMouse.wife := miniMouse; miniMouse.husband:=donaldDuck;
(二)多值逆属性 • 利用多值(集合)逆属性来实现对象间1:N联系的冗余表示,例如递归组合属性super与sub(多值)间的互逆的联系。 • 示例:用户界面窗口的设计——(无重叠的全包含窗口) — 窗口:用一个矩形框表示 —窗口之间是全包含的联系
r1 r11 其中: • r1包含r11、r12 且r11<r1 • r1不直接包含 r111, r111被r11直接包含 r111 r12 r112
type Rectangle is body [ height,length:float; contains:{Rectangle} ]; … end type Rectangle; 其中联系属性contains是一个多值集合属性,其元素为矩形框对象。
现定义contains的一个逆关系containsIn,其约束为:现定义contains的一个逆关系containsIn,其约束为: 若两个窗口对象r,r’具有r contains r’,则 r’ containsIn r, 即 containsIn(r’)={r| r’∈contains(r)} 最多仅由一个矩形r直接包含r’。 r111 r11 r112 r1 r12
包含一对互逆联系属性的窗口类型定义如下: type Rectangle is body [ height,length:float; contains:{Rectangle} inverse Rectangle$containedIn; containedIn:Rectangle inverse Rectangle$contains; ]; … end type Rectangle;
§9.6 复合对象引用的支持 • GOM支持对象间引用的更复杂的语义描述 • 引用的分类 — 弱引用: (weak reference)两个对象o1,o2除了它们之间存在一个引用联系外,没有任何其它的语义约束,即它们在同一个语义层次上是独立的两个实体,则称o1,o2间是一个弱引用 — 复合对象引用:(composite reference) 复合对象对部分对象的引用具有复杂的语义约束。
复合对象引用的语义分类 • 依赖/独立 Dependent/Independent • 专有/共享 Exclusive/Shared • 它们组合成了四种复合对象的引用语义
依赖—专有复合对象引用(最严格的语义引用) • 语义表示:该引用保证部分对象仅仅可能是一个复合对象的成份 • 一致性约束:部分对象当且仅当它所依赖的一个复合对象存在时才存在, • 约束的实现— 复合对象与部分对象的删除要捆绑进行 • 示例:
1. type computer is body [ cpu: dependent exclusive processor; … ]; end type computer; 说明:⑴cpu芯片与某主板共存亡,不被共享 ⑵不排除处理器主板上还可以有其他器件,如内存片则不是依赖主板的器件 2. 大楼与大楼内房间的关系
独立— 专有复合对象引用 • 语义表示:部分对象仅与一个复合对象关联,但它有自己的独立性 • 一致性约束:部分对象不允许共享;当主对象删除时,部分对象允许在对象库中独立存在 • 例:
type Automobile is body [ engine : independent exclusive Motor ; … ]; end type Automobile; 说明:⑴汽车引擎只为一台汽车所专用 ⑵引擎可以被复用(由一台汽车转到另一台)
依赖— 共享复合对象的引用 • 语义表示:部分对象可以共享,但它仍然是依赖于被关联的复合对象的存在而存在 • 一致性约束:部分对象的删除取决于所有引用它的复合对象的删除 • 示例:
1. type Document is body [ chapter : dependent shared Chapter; … ]; end type Document; 说明:文档的“章”可以共享,但当所有引用它的章被删除时,“章”的内容也自然不再存在 2. 客户档案依赖合同而存在 — 依赖 一个客户可以签多份合同 — 共享 当所有合同到期后,该客户也就不再出现
独立— 共享复合对象的引用 • 语义表示:部分对象即是共享的也是独立的(约束最弱) • 示例:发动机设计图— 共享的部分对象可以用在不同的汽车设计中;当汽车型号更新换代了,发动机设计仍然需要保存 type CarDesign is body [ engineDesign : independent shared MotorDesihn; ...] end type CarDesign;