分享
 
 
 

VB.Net中文教程(6) 母子对象关系

王朝vb·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

请注意 ......

著作权所有人:物泽计算机事业股份有限公司、

MISOO对象技术顾问团队、对象导向杂志作者、等。

u本文件摘自 对象导向杂志、精通对象观念与技术等书籍著作。

u本文件仅供您的参阅,请遵守著作权法,不得做其它商业用途。

主题: 母子对象关系

副题: Whole-Part关系

?????? 内容 ??????

v 1. 特殊Whole-Part关系

---- 母子对象关系

v 2. 母子对象谁先诞生﹖

v 3. 类别继承与母子对象

1. 特殊Whole-Part关系

---- 母子对象关系

大家已经熟悉父子类别关系﹐也就是「继承」关系了。于此说明另一种常见关系── 母子对象。一般称之为「组合/部分」关系。日常生活中﹐处处可见到这种母子对象。例如﹐客厅内有沙发、桌子、椅子等等。客厅是母对象﹐沙发、桌子、椅子是子对象。再如计算机屏幕上的窗口内有按钮、选择表、对话盒等等。窗口是母对象﹐按钮、选择表是子对象。于此将说明如何建立母子对象关系。有了关系﹐母子就能互相沟通了。母子对象之间﹐如何沟通呢﹖也就是说﹐母对象如何呼叫子对象的程序呢﹖反过来﹐子对象如何呼叫母对象的程序呢﹖欲呼叫对方的程序﹐必先与对方建立关系才行。因之﹐如何建立母子对象关系﹐是顶重要之课题﹗

请先看个例子﹐有两个类别──Room和Desk。若Room代表房间﹐Desk代表房间内的桌子﹐则它们会诞生母子对象﹕

通常﹐您会依房间的大小来决定桌子的大小。因之﹐Desk对象应跟Room对象沟通﹐取得房间的大小﹐才决定自己的大小。若有个Room之参考﹐则Desk对象就能跟Room对象沟通了。于是﹐可设计下述VB程序:

'ex01.bas

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

'----------------------------------------------------

Class Room

Protected rSize As Double

Shared motherObject As Room

Public Sub New()

motherObject = Me

End Sub

Shared Function GetMother() As Room

GetMother = motherObject

End Function

Public Function GetSize() As Double

GetSize = rSize

End Function

End Class

Class Desk

Protected dSize As Double

Public Sub New()

dSize = Room.GetMother().GetSize() * 0.18

End Sub

Public Function GetSize() As Double

GetSize = dSize

End Function

End Class

'----------------------------------------------------

Class MyRoom

Inherits Room

Private rd As Desk

Public Sub New()

rSize = 100

rd = New Desk()

End Sub

Public Sub Show()

MessageBox.Show("Room Size: " + str(rSize))

MessageBox.Show("Desk Size: " + str(rd.GetSize()))

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 r As New MyRoom()

r.Show()

End Sub

End Class

此程序输出:

Room Size: 100

Desk Size: 18

Desk类别内之指令──

Room.GetMother().GetSize()

就是Desk对象与Room对象之沟通了。MyRoom类别有个rd参考﹐指向子对象﹐如下﹕

母对象经由rd参考来跟子对象沟通。反过来﹐子对象经由Room.GetMother()参考跟母对象沟通。

2. 母子对象谁先诞生﹖

在VB里﹐有时候子对象比母对象早诞生完成。就像建造房子﹐建到半途﹐改而建造桌子﹐桌子建好了﹐再继续把房子建完成。由于这不太合乎人们的日常生活习惯﹐令人感到困惑﹗在计算机软件上﹐也有类似的冲突。例如﹐在Windows 下﹐母窗口建好了﹐才建立窗内的按钮、选择表等子对象。但VB有时并非如此﹗因之﹐如何化解这冲突﹐是个重要的话题。兹拿上小节的例子来说明吧﹗该例子中﹐其诞生对象之过程为﹕

Step 1: 先诞生母对象。

Step 2: 接着建立子对象。

这过程合乎人们的习惯﹐是美好的。其原因是﹕MyRoom类别在其建构者New()程序里呼叫Desk的New()诞生Desk子对象。假若您写下述程序﹐就出问题了﹗

'ex02.bas

'Some error here!

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

'----------------------------------------------------

Class Room

Protected rSize As Double

Shared motherObject As Room

Public Sub New()

motherObject = Me

End Sub

Shared Function GetMother() As Room

GetMother = motherObject

End Function

Public Function GetSize() As Double

GetSize = rSize

End Function

End Class

Class Desk

Protected dSize As Double

Public Sub New()

dSize = Room.GetMother().GetSize() * 0.18

End Sub

Public Function GetSize() As Double

GetSize = dSize

End Function

End Class

'----------------------------------------------------

Class MyRoom

Inherits Room

Private rd As New Desk()

Public Sub New()

rSize = 100

End Sub

Public Sub Show()

MessageBox.Show("Room Size: " + str(rSize))

MessageBox.Show("Desk Size: " + str(rd.GetSize()))

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 r As New MyRoom()

r.Show()

End Sub

End Class

其对象之建造过程为﹕

Step 1: 指令──

Dim r As New MyRoom()

呼叫MyRoom()建构者New()。它再呼叫Room()建构者New()将Room部分建好。

Step 2: 执行指令──

Private rd As New Desk()

呼叫Desk建构者New()﹐建好Desk子对象。此时会执行指令──

dSize = Room.GetMother().GetSize() * 0.18

Step 3: MyRoom建构者New() 继续将母对象建完成。

此时会执行指令── rSize=100

其中,GetSize()程序会取出rSize 值﹐但那时还未执行rSize=100 指令﹐那来

的rSize 值呢﹖所以出问题了。此程序可能输出如下错误结果﹕

Room Size: 100

Desk Size: 0

如何解决上述问题呢﹖常见方法是﹕

把会出问题的指令﹐从建构者程序中提出来﹐放到另一程序里。

例如下述程序:

'ex03.bas

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

'----------------------------------------------------

Class Room

Protected rSize As Double

Shared motherObject As Room

Shared Function GetMother() As Room

GetMother = motherObject

End Function

Public Overridable Sub Create()

motherObject = Me

End Sub

Public Function GetSize() As Double

GetSize = rSize

End Function

End Class

Class Desk

Protected dSize As Double

Public Sub Create()

dSize = Room.GetMother().GetSize() * 0.18

End Sub

Public Function GetSize() As Double

GetSize = dSize

End Function

End Class

'----------------------------------------------------

Class MyRoom

Inherits Room

Private rd As New Desk()

Public Sub New()

Me.Create()

End Sub

Public Overrides Sub Create()

MyBase.Create()

rSize = 100

rd.Create()

End Sub

Public Sub Show()

MessageBox.Show("Room Size: " + str(rSize))

MessageBox.Show("Desk Size: " + str(rd.GetSize()))

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 r As New MyRoom()

r.Show()

End Sub

End Class

此程序输出:

Room Size: 100

Desk Size: 18

像指令── dSize = Room.GetMother().GetSize() * 0.18﹐已挪到新设的Create()程序里。待母对象完全建好了﹐才会呼叫这Create()程序﹐GetSize() 就能取得正确值了。MyRoom的New()呼叫Create()程序时﹐母子对象皆已建造完成了。Create()内部依人们的习惯来设定对象之值,例如建立母子对象之关系。

如此就不会出问题了。

New()与Create()分离之后,MyRoom类别里的指令:

Class MyRoom

Inherits Room

Private rd As New Desk()

Public Sub New()

Me.Create()

End Sub

........

也能写为:

Class MyRoom

Inherits Room

Private rd As Desk

Public Sub New()

rd = New Desk()

Me.Create()

End Sub

........

只要确保Desk类别的指令──

dSize = Room.GetMother().GetSize() * 0.18

是在MyRoom类别的指令──

rSize = 100

之后执行即可了。

上述的子对象是透过Shared 程序来取得母对象的参考值﹐然后才跟母对象沟通。如果不透过Shared程序,也可以采取下述方法:

'ex04.bas

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

'----------------------------------------------------

Class Room

Protected rSize As Double

Public Overridable Sub Create()

End Sub

Public Function GetSize() As Double

GetSize = rSize

End Function

End Class

Class Desk

Protected dSize As Double

Protected myMother As Room

Public Sub Create(ByVal mo As Room)

myMother = mo

dSize = myMother.GetSize() * 0.18

End Sub

Public Function GetSize() As Double

GetSize = dSize

End Function

End Class

'----------------------------------------------------

Class MyRoom

Inherits Room

Private rd As Desk

Public Sub New()

rd = New Desk()

Me.Create()

End Sub

Public Overrides Sub Create()

rSize = 100

rd.Create(Me)

End Sub

Public Sub Show()

MessageBox.Show("Room Size: " + str(rSize))

MessageBox.Show("Desk Size: " + str(rd.GetSize()))

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 r As New MyRoom()

r.Show()

End Sub

End Class

此程序输出:

Room Size: 100

Desk Size: 18

Desk之对象含个参考 myMother ﹐指向其母对象。这项关系是在母子对象皆建好时﹐才由Create()程序所建立的。于是﹐建立出母子对象之关系﹕

综上所述,当MyRoom类别使用如下指令──

Private rd As New Desk()

时,才必须把New()与Create()分离。如果使用如下指令──

Private rd As Desk

Public Sub New()

rd = New Desk()

.....

End Sub

就不必分离了,原因是:New()与Create()的执行顺序是一致的,例如两者可合并如下的VB程序:

'ex05.bas

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

'----------------------------------------------------

Class Room

Protected rSize As Double

Public Function GetSize() As Double

GetSize = rSize

End Function

End Class

Class Desk

Protected dSize As Double

Protected myMother As Room

Public Sub New(ByVal mo As Room)

myMother = mo

dSize = myMother.GetSize() * 0.18

End Sub

Public Function GetSize() As Double

GetSize = dSize

End Function

End Class

'----------------------------------------------------

Class MyRoom

Inherits Room

Private rd As Desk

Public Sub New()

rSize = 100

rd = New Desk(Me)

End Sub

Public Sub Show()

MessageBox.Show("Room Size: " + str(rSize))

MessageBox.Show("Desk Size: " + str(rd.GetSize()))

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 r As New MyRoom()

r.Show()

End Sub

End Class

此程序输出:

Room Size: 100

Desk Size: 18

3. 特类别继承与母子对象

您已很熟悉父子类别关系了﹐这继承关系的另一面是母子对象关系。例如﹐

'ex06.bas

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

'----------------------------------------------------

Class Room

Private mother As MyRoom

Public Sub New(ByVal mo As MyRoom)

mother = mo

End Sub

Public Function GetID() As String

GetID = mother.yourID()

End Function

End Class

Class MyRoom

Inherits Room

Public Sub New()

MyBase.New(Me)

End Sub

Public Function yourID() As String

yourID = "VIP888"

End Function

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 r As New MyRoom()

MessageBox.Show(r.GetID())

End Sub

End Class

此程序输出﹕

VIP888

MyRoom()建构者New()将Me值给 Room的mother参考。于是mother参考到母对象r。Room类别是MyRoom之父类别﹐但Room之对象却是MyRoom之子对象。

如果将上述Room的指令:

Public Function GetID() As String

GetID = mother.yourID()

End Function

更改为:

Public Function GetID() As String

GetID = Me.yourID() 'Error!!

End Function

就错了。因为Room类别里没有定义yourID()程序。事实上,VB的继承机制里已经有母对象的参考值了,VB的Overridable机制就是基于它而呼叫到子类别(母对象)的程序的。例如上述程序相当于:

'ex07.bas

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

'----------------------------------------------------

Class Room

Public Function GetID() As String

GetID = Me.yourID()

End Function

Public Overridable Function yourID() As String

End Function

End Class

Class MyRoom

Inherits Room

Public Sub New()

MyBase.New()

End Sub

Public Overrides Function yourID() As String

yourID = "VIP888"

End Function

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 r As New MyRoom()

MessageBox.Show(r.GetID())

End Sub

End Class

此程序输出﹕

VIP888

上述ex07.bas比ex06.bas好的地方是:

ex06.bas程序的Room类别里面用到MyRoom的名称。而ex07.bas程序的Room类别里面并没用到MyRoom的名称,因此Room类别可以先设计,MyRoom类别能后来才设计,这是继承机制的目的之一。不过,如果您一定不想用继承与Overridable概念的话,可使用VB的Interface机制来改善ex06.bas程序,如下:

'ex08.bas

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

'----------------------------------------------------

Interface IMyRoom

Function yourID() As String

End Interface

Class Room

Private mother As IMyRoom

Public Sub New(ByVal mo As IMyRoom)

mother = mo

End Sub

Public Function GetID() As String

GetID = "RoomID: " + mother.yourID()

End Function

End Class

Class MyRoom

Implements IMyRoom

Private base As Room

Public Sub New()

base = New Room(Me)

End Sub

Public Function yourID() As String Implements IMyRoom.yourID

yourID = "VIP888"

End Function

Public Function GetID() As String

GetID = base.GetID()

End Function

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 r As New MyRoom()

MessageBox.Show(r.GetID())

End Sub

End Class

此程序输出﹕

RoomID: VIP888

一般使用委托(Delegation)来代替继承时,常用的手法。然而上述ex08.bas程序的MyRoom类别里面用到了Room名称,如果您不希望如此,可定义一个IRoom接口,供MyRoom类别使用,如下程序:

'ex09.bas

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

'----------------------------------------------------

Interface IMyRoom

Function yourID() As String

End Interface

Interface IRoom

Function GetID() As String

Sub Connect(ByVal m As IMyRoom)

End Interface

Class Room

Implements IRoom

Private motherObject As IMyRoom

Public Function GetID() As String Implements IRoom.GetID

GetID = motherObject.yourID() + " ***"

End Function

Public Sub Connect(ByVal m As IMyRoom) Implements IRoom.Connect

motherObject = m

End Sub

End Class

Class MyRoom

Implements IMyRoom

Private base As IRoom

Public Sub Connect(ByVal r As IRoom)

base = r

r.Connect(Me)

End Sub

Public Function yourID() As String Implements IMyRoom.yourID

yourID = "Dog888"

End Function

Public Function GetID() As String

GetID = base.GetID()

End Function

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 my As New MyRoom()

Dim base As New Room()

my.Connect(base)

MessageBox.Show(my.GetID())

End Sub

End Class

此程序输出﹕

RoomID: VIP888

Room类别里面没用到MyRoom名称,而且MyRoom类别里没有用到Room名,因此两个类别可独立设计。这是分布式组件软件,如MTS(Microsoft transaction server)等系统里的常用手法。n

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有