VB.Net中文教程(6) 母子物件關係 (轉)
請注意 ......
著作權所有人:物澤事業股份有限公司、
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.s
'----------------------------------------------------
Class Room
Protected rSize As Double
Shared mother 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 FoDesigner.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrs dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " 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( transaction server)等裡的常用手法。n
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988978/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- VB.Net中文教程(13) Whole-Part關係 (轉)
- VB.Net中文教程(4) 類別繼承(Inheritance)關係 (轉)繼承
- VB.Net中文教程(11) Prototype樣式 (轉)
- VB.Net中文教程(2) Composite樣式 (轉)
- VB.Net中文教程(7) Me參考值 (轉)
- VB.Net中文教程(5)程式多重定義 (轉)
- VB.Net中文教程(3) 繼承與封裝性 (轉)繼承封裝
- VB.Net中文教程(1) 類別與封裝性 (轉)封裝
- VB.Net中文教程(9) 重新定義(Overriding)程式 (轉)
- VB.NET中物件的克隆 (轉)物件
- 物件怎麼轉化為關係的物件
- 中國式管理-人際關係學6(轉)
- 《ElasticSearch6.x實戰教程》之父-子關係文件Elasticsearch
- java物件關係對映ROMJava物件
- 深入理解物件導向,物件導向3個特性7個原則6種關係物件
- 物件導向程式設計程式碼詳解(依賴關係,關聯關係,組合關係)物件程式設計
- VB.NET中的物件導向程式設計特徵 (轉)物件程式設計特徵
- JSON 與 JS 物件的關係JSON物件
- 5. JPA物件繼承關係物件繼承
- MongoDB、Java與物件關係對映MongoDBJava物件
- 不同層之間的物件關係物件
- MongoDB、Java和物件關係對映MongoDBJava物件
- 關係運算子(轉)
- 【UML入門教程】——UML關係
- 從VB 6到VB.NET——窗體特殊應用 (轉)
- oracle 邏輯物件與物理物件對應關係圖Oracle物件
- 物件關係對映(ORM)簡單看懂物件ORM
- hibernate物件關係的翻譯稿物件
- ECMAScript 6教程 (二) 物件和函式物件函式
- 品牌關係管理(轉載)
- 互惠關係定律(轉載)
- ER模型轉關係模式模型模式
- Emacs 教程中文版(轉)Mac
- 【物件導向依賴關係概念總結】物件導向程式設計的五種依賴關係物件程式設計
- 請教關於物件與關係間的對映物件
- 類圖的6大關係詳解
- CMMI和6Sigma的關係
- MyBatis加強(1)~myBatis物件關係對映(多對一關係、一對多關係)、延遲/懶載入MyBatis物件