VB.Net中文教程(13) Whole-Part关系
2024-07-10 13:02:42
供稿:网友
 
主题: whole-part关系
?????????? 内容 ??????????
v 1. 对象whole-part关系
v 2. 组合/部分关系
v 3. 包含者/内容关系
v 4. 集合/成员关系
 
 
1. 对象whole-part关系
 类别继承(class inheritance)和对象组合(object composition)是软件再使用(reuse)的两大法宝。类别继承就是建立父、子类别之关系﹔例如﹐「学生」可分为「大学生」、「中学生」和「小学生」三类别﹐其继承关系图标如下﹕
 
 图1、 以uml表达类别继承
 对象组合的目的是﹕创造「复合对象」(composite object)﹔例如﹐医院内含医师和护士等﹐其组合关系图标如下﹕
 
 图2、 以uml表达对象组合
继承与组合两大法宝能联合使用﹐以组织庞大的软件系统。例如﹐汽车分为客车、卡车、轿车等子类别﹐而且汽车内含引擎、车体、轮胎等零件﹐则此汽车系统图标如下图3和图4﹕
 
 图3、 汽车的类别继承体系
 
 图4、 汽车的对象组合关系
本节里﹐将进一步分析与说明对象组合方法。尤顿(yourdon) 认为﹐常见组合关系有三﹕
 1) 组合╱部分(assembly-parts)关系。
 2) 包含╱内容(container-contents)关系。
 3) 集合╱成员(collection-members)关系。
 
 
2. 组合/部分关系
 组合/部分关系﹐常称为apo(a part of)关系﹔例如﹐汽车是「组合」﹐其内含各零件是「部分」。门是房子的一部分﹐所以房子是「组合」﹐门是「部分」﹔此外﹐窗子也是房子的「部分」。这房子与门窗之关系﹐图标如下﹕
 
 图5、 房子的对象组合关系
以vb表达如下﹕
'ex01.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'---------------------------------------------------------------------------------
class house
 class door
 public size as double
 public sub new(byval s as double)
 size = s
 end sub
 end class
 
 class window
 public size as double
 public sub new(byval s as double)
 size = s
 end sub
 end class
 
 private dr as door
 private win as window
 public sub new()
 dr = new door(50)
 win = new window(100)
 end sub
 public sub show()
 messagebox.show("door: " + str(dr.size) + " win: " + str(win.size))
 end sub
end class
'---------------------------------------------------------------------------------------------------
public class form1
 inherits system.winforms.form
 
 public sub new()
 mybase.new()
 form1 = me
 'this call is required by the win form designer.
 initializecomponent()
 'todo: add any initialization after the initializecomponent() call
 end sub
 'form overrides dispose to clean up the component list.
 public overrides sub dispose()
 mybase.dispose()
 components.dispose()
 end sub
#region " windows form designer generated code "
 ......
#end region
 protected sub form1_click(byval sender as object, byval
 e as system.eventargs)
 dim h as new house()
 h.show()
 end sub
end class
以此程序输出如下﹕
 door: 50 win: 100
house 之对象诞生后﹐立即诞生内含之door对象和window对象。例如﹐宣告指令──
 dim h as new house()
此时﹐h 对象诞生了﹐其内含之dr 和win对象亦诞生了。
 
此h 通称为「组合对象」(composite object)﹐而dr 和win 则称为「部分对象」(component object)。这种关系具有一项特色﹕组合对象与部分对象的寿命应该是一致的。
 在逻辑(logical)意义上,这house 结构中﹐门和窗随着房子而具有「生死与共」之亲蜜关系,也就是寿命一致。在计算机实体(physical)表达时,house 之对象并不「真正」包含door及window之对象﹐只是利用两个参考指向它们。所以上图也可想象如下:
 
上述两种实体结构皆表达了「组合/部分」关系。请再看个例子:
'ex02.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------
class person
 private p_name as string
 private p_age as integer
 
 public sub new(byval na as string, byval a as integer)
 p_name = na
 p_age = a
 end sub
 public function isequal(byval obj as person) as integer
 dim k as integer = 0
 if me.p_name = obj.p_name then
 k = 1
 end if
 isequal = k
 end function
 public sub show()
 messagebox.show(me.p_name + ", " + str(me.p_age))
 end sub
end class
'---------------------------------------------------------------------------------
public class form1
 inherits system.winforms.form
 
 public sub new()
 mybase.new()
 form1 = me
 'this call is required by the win form designer.
 initializecomponent()
 'todo: add any initialization after the initializecomponent() call
 end sub
 'form overrides dispose to clean up the component list.
 public overrides sub dispose()
 mybase.dispose()
 components.dispose()
 end sub
#region " windows form designer generated code "
 .........
#end region
 protected sub form1_click(byval sender as object, 
 byval e as system.eventargs)
 dim a as new person("alvin", 35)
 dim b as new person("david", 25)
 a.show()
 b.show()
 messagebox.show(str(a.isequal(b)))
 messagebox.show(str(b.isequal(new person("david", 32))))
 end sub
end class
此程序输出﹕
 alvin, 35 
david, 25 
0 
1 
「组合」对象之建构者new()程序诞生「部分」对象。此a 、b 两对象之内容为﹕
 
 
在isequal()程序里,两个对象拿其p_name 值来比较。例如﹐a.p_name 值是"alvin" ﹐而b.p_name 值是"david" ﹐所以a.isequal(b)表达式之值为0 (false)。
 
 
 
3. 包含者/内容关系
 上节的house 结构中﹐门和窗随着房子而具有「生死与共」之亲蜜关系。然而﹐日常生活中﹐常见类似但并不如此亲蜜的情形。例如﹐飞行员坐于飞机驾驶仓内开飞机﹔司机在汽车内驾驶汽车﹔客人乘座于巴士内等等。司机不是汽车的零件﹐客人亦非巴士之组件﹐所以汽车与司机之间并非「组合/部分」关系﹔然而﹐汽车的确包含着司机﹐因之称为「包含者/内容」(container-contents)关系。
 司机和汽车为独立之对象﹐不像引擎一直包含于汽车内﹔于驾驶汽车时﹐司机才被包含于汽车内。显然地﹐司机与汽车之寿命不一样长。「包含者/内容」关系是一种特殊的组合结构﹐其图标方法与「组合/部分」关系相同。例如﹐
 
此图表达了﹕
 ◎ 汽车与引擎之间为「组合/部分」关系。
 ◎ 汽车与司机之间为「包含者/内容」关系。
以vb表达如下﹕
'ex03.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------
class driver
 private name as string
 public sub new(byval na as string)
 name = na
 end sub
 public sub show()
 messagebox.show("driver: " + name)
 end sub
end class
class car
 class engine
 public model as string
 public sub new(byval mdl as string)
 model = mdl
 end sub
 end class
 
 private e as engine
 private dr as driver
 public sub new()
 e = new engine("honda")
 end sub
 public sub assignto(byval d as driver)
 dr = d
 end sub
 public sub show()
 messagebox.show("engine: " + e.model)
 dr.show()
 end sub
end class
'----------------------------------------------------
public class form1
 inherits system.winforms.form
 public sub new()
 mybase.new()
 form1 = me
 'this call is required by the win form designer.
 initializecomponent()
 'todo: add any initialization after the initializecomponent() call
 end sub
 'form overrides dispose to clean up the component list.
 public overrides sub dispose()
 mybase.dispose()
 components.dispose()
 end sub
#region " windows form designer generated code "
 .......
#end region
 protected sub form1_click(byval sender as object, byval e as system.eventargs)
 dim civic as new car()
 dim d1 as new driver("wang")
 dim d2 as new driver("kao")
 civic.assignto(d1)
 civic.show()
 civic.assignto(d2)
 civic.show()
 end sub
end class
此程序输出﹕
 model: honda
 driver: wang
 model: honda
 model" kao
car之对象诞生后﹐也诞生engine之对象e ﹔同时立即指定司机﹐如下指令﹕
 
 dim civic as new car()
 dim d1 as new driver("wang")
 ..... 
 civic.assignto(d1)
 .....
日常生活中的常见情况﹕汽车对象诞生时﹐不须立即指定司机对象。例如﹐汽车出厂时或闲置时并无司机﹐且汽车经常更换司机。此情形下﹐应先诞生civic对象和d1对象,如下:
 
此时,未立即指定司机﹔而必要时才以assignto()程序指定司机。例如,将d1指定给civic对象﹐就令civic内之参考变量dr指向d1 对象,如下:
 
 上述程序里,d1、d2及civic 对象之间﹐谁先诞生并无关紧要﹐各独立存在。指令──civic.assignto(d1) 将d1司机指定给civic 对象﹔另一指令──civic.assignto(d2)表示﹕改由d2担任civic 之司机。
 此car 类别以参考变量e来指向engine之对象。现在﹐兹拿上节的person类别做为例子﹐如果某人(person 之对象)结婚了﹐就有配偶﹔反之尚未结婚时﹐则无配偶。此时﹐应将person类别之定义修改如下﹐以表达这种「配偶」关系﹕
'ex04.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------
class person
 private p_name as string
 private p_age as integer
 private p_spouse as person
 
 public sub new(byval na as string, byval a as integer)
 p_name = na
 p_age = a
 end sub
 public sub spouse(byval sp as person)
 p_spouse = sp
 sp.p_spouse = me
 end sub
 public sub show()
 messagebox.show(me.p_name + ", " + str(me.p_age) 
 + ", sp: " + me.p_spouse.p_name)
 end sub
end class
'----------------------------------------------------
public class form1
 inherits system.winforms.form
 
 public sub new()
 mybase.new()
 
 form1 = me
 'this call is required by the win form designer.
 initializecomponent()
 'todo: add any initialization after the initializecomponent() call
 end sub
 'form overrides dispose to clean up the component list.
 public overrides sub dispose()
 mybase.dispose()
 components.dispose()
 end sub
#region " windows form designer generated code "
 ...... 
#end region
 protected sub form1_click(byval sender as object, byval
 e as system.eventargs)
 dim x as new person("david", 32)
 dim y as new person("hellen", 24)
 x.spouse(y)
 x.show()
 y.show()
 end sub
end class
此程序输出﹕
david, 32, sp: hellen
hellen, 24, sp: david
 资料成员p_spouse指向配偶﹐而配偶亦为person之对象。所以p_spouse之型态应为person。一个人刚诞生时并无配偶﹐到结婚时才有配偶﹐所以藉spouce()来建立配偶关系。对象x 与y 结婚之后﹐互为对方之配偶。所以x.p_spouse指向y ﹐而y.p_spouse则指向x 。此时﹐x 和y 之内容如下﹕
 
 
于是这person类别表达了「婚姻」关系。
 
 
4. 集合/成员关系
 集合意谓着「团体」(group) ﹐由其成员(member)组成的群体。例如﹐学校里的社团内有团员﹔公司的销售部含有推销人员。这团体并不像汽车实际包含着司机﹐而只是其成员之集合而已。这情形﹐统称为「集合/成员」(collection-members)关系。
 有趣的是﹕在企业活动中﹐人们规划的方案﹐含许多小方案﹔则大方案是由小方案所组成。例如﹐东北亚旅行团的行程表包括在日本的观光行程、在韩国的观光行程和在香港的观光行程。这总行程表图标如下﹕
 
 总行程是次行程(或称段行程)之集合﹐这是「集合/成员」关系。
 
此外﹐棒球队是由经理、教练和球员组成﹕订单中含若干产品项目﹐皆为集合/成员关系。实际写程序时﹐不需明确划分「包含者/内容」和「集合/成员」两种关系。其原因是﹕集合与成员之间亦可互为独立﹐不具「生死与共」之亲蜜关系﹔例如﹐「香港观光行程」是独立存在的﹐它既可含于东北亚总行程中﹐又可含于东南亚旅行团的总行程中。因之﹐「集合/成员」关系是一种特殊的「组合」(composition) 结构。
 兹拿上节person类别做为例子﹐如果person之对象会加入club(俱乐部)成为俱乐部的会员﹐则club与person之关系为「集合/成员」关系。兹定义club类别如下﹕
'ex05.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
imports system.collections
'----------------------------------------------------
class person
 private p_name as string
 private p_age as integer
 
 public sub new(byval na as string, byval a as integer)
 p_name = na
 p_age = a
 end sub
 public sub display()
 messagebox.show(me.p_name + ", " + str(me.p_age))
 end sub
end class
class club
 private c_name as string
 private pa as arraylist
 
 public sub new(byval na as string)
 c_name = na
 pa = new arraylist()
 end sub
 public sub join(byval p as person)
 pa.add(p)
 end sub
 public sub display()
 messagebox.show("club: " + me.c_name + " has member:")
 dim p as person
 for each p in pa
 p.display()
 next
 end sub
end class
'-------------------------------------------------------------------------------
public class form1
 inherits system.winforms.form
 
 public sub new()
 mybase.new()
 form1 = me
 'this call is required by the win form designer.
 initializecomponent()
 'todo: add any initialization after the initializecomponent() call
 end sub
 'form overrides dispose to clean up the component list.
 public overrides sub dispose()
 mybase.dispose()
 components.dispose()
 end sub
#region " windows form designer generated code "
 ...... 
#end region
 protected sub form1_click(byval sender as object, byval e as system.eventargs)
 dim x as new club("sogo")
 dim a as new person("alvin", 32)
 dim b as new person("judy", 28)
 x.join(a)
 x.join(b)
 x.display()
 end sub
end class
此程序输出﹕
club: sogo has member:
alvin, 32
judy, 28
c_name 指向strclass之对象﹐这对象内含俱乐部之名称。pa指向arraylist之对象﹐这对象可包含许多会员(person)对象。join()程序将person之对象存入pa所指的arraylist对象中。
 club之对象含arraylist之对象﹐此集合对象(collections)含有person之对象﹐表达了「集合/成员」关系。例如﹐x 对象内含a 和b 对象。
 
 此图表示﹕"sogo"俱乐部共有"alvin" 和"judy"两个会员﹐亦即x 是「集合」﹐而a 和b 是「成员」(member)。
 值得注意﹕这软件是利用已有类别──strclass及integer组合成应用类别──person。再利用person类别及arraylist 类别组合成更复杂之应用类别──club。未来﹐可利用club及其它类别构筑更大的应用类别﹐依此类推﹐便能创造庞大又可靠的软件了。例如:
'ex06.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
imports system.collections
'----------------------------------------------------
class person
 private p_name as string
 private p_age as integer
 public sub new(byval na as string, byval a as integer)
 p_name = na
 p_age = a
 end sub
 public sub display()
 messagebox.show(me.p_name + ", " + str(me.p_age))
 end sub
end class
class club
 private c_name as string
 private pa as arraylist
 
 public sub new(byval na as string)
 c_name = na
 pa = new arraylist()
 end sub
 public sub join(byval p as person)
 pa.add(p)
 end sub
 public sub display()
 messagebox.show("club: " + me.c_name + " has member:")
 dim p as person
 for each p in pa
 p.display()
 next
 end sub
end class
'----------------------------------------------------
public class form1
 inherits system.winforms.form
 
 public sub new()
 mybase.new()
 
 form1 = me
 'this call is required by the win form designer.
 initializecomponent()
 'todo: add any initialization after the initializecomponent() call
 end sub
 'form overrides dispose to clean up the component list.
 public overrides sub dispose()
 mybase.dispose()
 components.dispose()
 end sub
#region " windows form designer generated code "
 ......
#end region
 protected sub form1_click(byval sender as object, byval e as system.eventargs)
 dim x(2) as club
 x(0) = new club("sogo")
 x(1) = new club("gold")
 dim a as new person("alvin", 32)
 dim b as new person("judy", 28)
 dim c as new person("bob", 38)
 x(0).join(a)
 x(0).join(b)
 x(1).join(b)
 x(1).join(c)
 x(0).display()
 x(1).display()
 end sub
end class
此程序输出:
club: sogo has member:
 alvin, 32
 judy, 28
club: gold has member:
 judy, 28
 bob, 38
 组合对象x 含"sogo"及"gold"两俱乐部﹐其中"gold"俱乐部拥有两个会员──"alvin" 及"judy"﹐而"sogo"俱乐部拥有两位会员──"judy"及"bob" 。x(0)代表"sogo"俱乐部﹐s(1)代表"gold"俱乐部﹐所以指令── s(0).join( a ) 表示a 加入"gold"俱乐部﹐成为其会员。n