教程|中文
主题: 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"