VB.Net中文教程(2) Composite樣式 (轉)
請注意 ......
著作權所有人:物澤事業股份有限公司、
MISOO技術顧問團隊、物件導向雜誌作者、等。
u本摘自 物件導向雜誌、精通物件觀念與技術等書籍著作。
u本檔案僅供您的參閱,請遵守著作權法,不得做其它商業用途。
主題: Composite樣式
副題: Whole-Part關係
?????????? 內容 ??????????
v 1. 從Whole-part關係談起
v 2.簡單的Whole-part關係
v 3.遞迴式Whole-part關係
v 4.以VB落實Composite樣式
1. 從Whole-part關係談起
回想傳統的師﹐常甚專注於撰寫(procedure) 來處理某些資料(data)﹐較少關心軟體的整體結構(architecture)。在現在的OO軟體中﹐把資料及其相關的程式結合在一起﹐封裝(encapsulate) 在物件之中。軟體師在使用物件時﹐通常把物件視為黑箱(black-box) ﹐不會關心於物件內部之細節﹔因之能專注於物件之間的關係。軟體師的主要工作﹐就是在於建立物件之間的互助合作(collaboration) 關係﹐為物件安排應盡之角色(role)﹐至於物件內部之細節﹐反而不頂重要。如此﹐可讓軟體師著重於軟體的整體架構上﹐而不會一頭栽程式序的細節之中。這避免了見樹不見林的缺點﹐放寬了軟體師的眼界﹐為軟體的多用途(reusability) 及彈性(flexibility) 著想﹐可創造長壽的軟體﹗
物件之間的常見關係有許多種﹐其中之一就是Whole-part關係。像一朵花是由花蕊、花瓣、襯葉等所構成的﹐這朵花是個「整體」(Whole)﹐而花蕊、花瓣等則是這整體的「一部分」(part)。再如﹐下圖的畫面上﹐Form1 物件包含著3 個控制物件(control) ﹐這些控制物件成為Form1 的一部分。因之﹐Form1 是個整體﹐而各控制物件則是Form1 物件的一部分。
圖1 、Form1 物件包含3 個控制物件
我們可使用UML圖形表示為﹕
圖2、Whole-part關係與繼承關係
這圖包括了Whole-part關係﹐以及繼承關係。
● 菱形 符號表示Whole-part關係﹔就是Form1 物件可包含有數個control 物件。
● 箭頭 符號表示繼承關係﹔就是control 物件可細分為數個種類。
本文專注於Whole-part關係﹐為Composite樣式建立基礎。Whole-part關係可分為兩種﹕
◎「部分」物件之個數是確定的。例如﹐1 輛汽車含有1 個方向盤﹐1 個Form物件含有1 個抬頭(caption) 物件﹐1 只青蛙有4 條腿等等。在這種確定情形﹐可視為下述「可變」情形的特例。
◎「部分」物件之個數是可變的。例如﹐1 個Form物件內含多個控制物件﹐1 棵樹含有成千上萬葉子﹐1 位學生的成績單上列有各科目的成績等等。這種Whole-part關係通常得藉集合(collection)物件來表達之﹐如的ArrayList物件就可派上用場了。
2. 簡單的Whole-part關係
最單純的Whole-part關係就是某物件「內含」(contain) 其它物件。例如﹐
s 1 張訂單上面列示著多個採購的產品專案
s 1 支棒球隊擁有數字教練及多位球員
s 學生的成績單上印有多項成績
s 1 篇文章是由許多句子所組成
s 螢幕上的選擇表(menu)內含數個選擇項
s 1 份考卷包含數十道考題
......
就拿訂單(order form)的例子來說﹐訂單上常列有多個採購專案(order line)。
圖3、 訂單的例子
每個採購專案通常包括有產品名稱、採購數量、金額等。為了簡單起見﹐假設採購專案只含產品名稱及金額兩個專案﹐可藉UML圖表示「訂單」與「採購專案」之間的Whole-part關係﹐如下圖所示﹕
圖4、以UML表達簡單的Whole-part關係
在以VB落實這個UML時,則可藉VB的ArrayList集合物件來實作(implement)「訂單」與「採購專案」之間的Whole-part關係﹐如下圖所示﹕
圖5、以UML表達簡單的Whole-part關係
現在的VB軟體師需要很習慣於掌握這種Whole-part關係﹐且常藉集合物件來表示之。請看實際的VB程式﹐其中定義Order 及OrderLine 兩個類別﹕
'ex01.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.s
Imports System.Collections
'----------------------------------------------------
Class OrderLine
Private pname As String
Private amt As Double
Public Sub New(ByVal na As String, ByVal am As Double)
pname = na
amt = am
End Sub
Public Function Name() As String
Name = pname
End Function
Public Function Amount() As Double
Amount = amt
End Function
End Class
Class Order
Private OrderID As String
Private lines As ArrayList
Public Sub New(ByVal id As String)
OrderID = id
lines = New ArrayList()
End Sub
Public Sub AddLine(ByVal ln As OrderLine)
lines.Add(ln)
End Sub
Public Function Amount() As Double
Dim total As Double = 0
Dim ln As OrderLine
For Each ln In lines
total = total + ln.Amount()
Next
Amount = total
End Function
Public Function getOrderID() As String
getOrderID = OrderID
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 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 " Windows Form Designer generated code "
......
#End Region
Protected Sub Form1_Click(ByVal sender As , ByVal
e As System.EventArgs)
Dim ord As New Order("Order777")
Dim pline As OrderLine
pline = New OrderLine("Pencil", 88.25)
ord.AddLine(pline)
pline = New OrderLine("Ballpen", 110.5)
ord.AddLine(pline)
Messagebox.Show(ord.getOrderID + "'s amount = " + str(ord.Amount()))
End Sub
End Class
此程式輸出:
Order777's cost = 198.75
在Order 類別中定義了lines變數﹐其型態ArrayList﹐表示lines將可代表1 個ArrayList之物件﹐其本質上就是lines變數,內含一個參考值﹐參考到ArrayList之物件。在Order類別的建構程式 ---- New()裡,誕生了ArrayList物件﹐並將參考值存入lines裡。各程式之定義如下﹕
Order 類別的Amount()程式計算出該訂單的總金額。AddLine() 則在訂單上新增一個採購專案。在Form1_Click()中﹐ord 物件內含一個lines集合物件﹐它容納2 個OrderLine物件。如此就表達了訂單與採購專案之間的Whole-part關係了。
上述程式相當於 -----
'ex02.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
Imports System.Collections
'----------------------------------------------------
Class Order
Class OrderLine
Public pname As String
Public amt As Double
End Class
Private OrderID As String
Private lines As ArrayList
Public Sub New(ByVal id As String)
OrderID = id
lines = New ArrayList()
End Sub
Public Sub AddLine(ByVal pna As String, ByVal am As Double)
Dim ln As OrderLine
ln = New OrderLine()
ln.pname = pna
ln.amt = am
lines.Add(ln)
End Sub
Public Function Amount() As Double
Dim total As Double = 0
Dim ln As OrderLine
For Each ln In lines
total = total + ln.amt
Next
Amount = total
End Function
Public Function getOrderID() As String
getOrderID = OrderID
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 ord As New Order("Order777")
ord.AddLine("Pencil", 88.25)
ord.AddLine("Ballpen", 110.5)
Messagebox.Show(ord.getOrderID + "'s amount = " + str(ord.Amount()))
End Sub
End Class
此程式輸出:
Order777's cost = 198.75
3. 遞迴式Whole-part關係
Whole-part關係內含別的Whole-part關係﹐且允許有多層次的Whole-part關係﹐通稱為遞迴式的Whole-part關係。在自然界中常見這種關係﹐例如﹐樹葉是樹的一部分﹐但樹葉又是個整體﹐其內含著葉脈、葉綠素等「部分」物件。
圖6、自然界的多層次Whole-part關係
在企業界﹐最典型的例子是「物件結構表」(bill of material簡稱BOM)﹐如下﹕
圖7、企業物料表(BOM)的Whole-part關係
乍看之下,這些結構似乎很複雜﹐但從這些圖形中﹐可看出這些物件可依其角色而分為兩類﹕
1. Leaf物件。如上圖裡的「白色」類別之物件﹐它們不具有Whole 之角色﹐只具有part之角色。這通稱為「基本」(primitive component) 。
2. Composite 物件。如上圖中的「灰色」類別之物件﹐它們具有Whole之角色﹐也可能具有part之角色。這通稱為「複合元件」(composite component) 。
因之﹐只需定義兩個類別──Leaf及Composite 類別即行。
4. 以VB落實Composite樣式
上述遞迴Whole-part關係是很常見的﹐是軟體設計師慣用的手藝。因之﹐在Gamma 的"Design Patterns" 一書〔注1 〕中﹐也將之收錄為重要的「樣式」(Pattern) 之1。 該書所畫的樣式結構圖如下圖:
圖8、Composite樣式
這樣式建議我們應定義Add() 、Remove()和GetChild()三個基本的可再定義的(overridable) 程式﹐以及其它的程式。專家們把這表示法視為樣式﹐就意謂著﹕這是專家們所認為最理想的表達方式。現在﹐實際以依循這個樣式來表達上述BOM 結構,必須定義下述類別:
u Part類別 ----- 對應到Component
u PiecePart類別 ----- 對應到Leaf
u AssemblyPart類別 ----- 對應到Composite
再將之落實為VB程式,如下:
'ex03.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
Imports System.Collections
'----------------------------------------------------
Interface IPart
Sub Add(ByVal p As IPart)
Function GetChild(ByVal n As Integer) As IPart
Function Cost() As Double
Function Name() As String
End Interface
Class Part
Private pname As String
Protected Sub New(ByVal na As String)
pname = na
End Sub
Protected Function getName() As String
getName = pname
End Function
End Class
Class PiecePart
Implements IPart
Inherits Part
Private pcost As Double
Public Sub New(ByVal na As String, ByVal c As Double)
MyBase.New(na)
pcost = c
End Sub
Public Sub Add(ByVal p As IPart) Implements IPart.Add
MessageBox.Show("Parts do not have Subparts")
End Sub
Public Function SubPart(ByVal n As Integer) As IPart Implements IPart.GetChild
SubPart = Nothing
End Function
Public Function Cost() As Double Implements IPart.Cost
Cost = pcost
End Function
Public Function Name() As String Implements IPart.Name
Name = MyBase.getName()
End Function
End Class
Class AssemblyPart
Implements IPart
Inherits Part
Private children As ArrayList
Public Sub New(ByVal na As String)
MyBase.New(na)
children = New ArrayList()
End Sub
Public Sub Add(ByVal p As IPart) Implements IPart.Add
children.Add(p)
End Sub
Public Function SubPart(ByVal n As Integer) As IPart Implements IPart.GetChild
Dim obj As Object
obj = children.Item(n)
SubPart = CType(obj, IPart)
End Function
Public Function Cost() As Double Implements IPart.Cost
Dim sum As Double
Dim ps As IPart
sum = 0
For Each ps In children
sum = sum + ps.Cost()
Next
Cost = sum
End Function
Public Function Name() As String Implements IPart.Name
Name = MyBase.getName()
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 aly1, aly2, p1, p2 As IPart
Dim ps As IPart
aly1 = New AssemblyPart("bulb")
p1 = New PiecePart("body", 88.25)
aly1.Add(p1)
p1 = New PiecePart("head", 100.5)
aly1.Add(p1)
aly2 = New AssemblyPart("light")
aly2.Add(aly1)
p1 = New PiecePart("cover", 10)
aly2.Add(p1)
Messagebox.Show(aly2.Name() + "'s cost = " + str(aly2.Cost()))
p1 = aly2.GetChild(0)
Messagebox.Show(p1.Name + "'s cost = " + str(p1.Cost()))
p2 = aly2.GetChild(1)
Messagebox.Show(p2.name + "'s cost = " + str(p2.Cost()))
p2 = p1.GetChild(0)
Messagebox.Show(p2.Name + "'s cost = " + str(p2.Cost()))
End Sub
End Class
此程式輸出: light's cost = 198.75
bulb's cost = 188.75
cover's cost = 10
body's cost = 88.25
PiecePart 代表最下層的基本物件。而AssemblyPart則代表中層的半成品物件元件﹐或代表成品。Part為一個抽象類別,定義PiecePart與AssemblyPart類別的共同部份(包括屬性和行為),供PiecePart與AssemblyPart子類別來繼承之。此外,提供一個介面IPart給Client使用,以封裝Part、PiecePart和AssemblyPart類別,創造Part、PiecePart和AssemblyPart類別的彈性調整空間,這是非常重要的。
Form1_Click()程式建立了有關「汽車車燈」的物件結構表﹕
圖8、VB程式所誕生的物件關係圖
p1 = aly2.GetChild(0)取出「燈泡」小物件﹐並由p1代表這個小物件。p2 = p1.GetChild(0) 取出「燈帽」小物件﹐並由p2代表之。依上述之樣式﹐可表達出無限層次的遞迴式Whole-part關係。
為了讓軟體能永續生存下去﹐必須特別重視軟體的組織與其整體架構(architecture)。於是﹐設計軟體時,必須專注於物件之間的互助合作關係。一旦建立了理想的關係﹐就可以讓物件之間互相傳遞訊息、互相溝通了。例如﹐Form1 物件傳送Cost訊息給aly2物件﹐aly2物件就依循ArrayList物件所建立的關係來將Cost訊息遞給內含之各小物件。當各小物件回報其成本金額﹐aly2將之累計再傳送回到Form1 物件﹐然後顯示在視窗畫面上。此刻﹐相信您已經進一步瞭解Whole-part關係﹐善用ArrayList集合類別來表達之,並更會運用VB來落實樣式,創造出更美好的軟體。■
[注1] Erich Gamma,Design Patterns: Elements of Reusable Object-Oriented Software, Addition-Wesley, 1995.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1004279/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- VB.Net中文教程(11) Prototype樣式 (轉)
- VB.Net中文教程(7) Me參考值 (轉)
- VB.Net中文教程(5)程式多重定義 (轉)
- VB.Net中文教程(6) 母子物件關係 (轉)物件
- VB.Net中文教程(13) Whole-Part關係 (轉)
- VB.Net中文教程(3) 繼承與封裝性 (轉)繼承封裝
- VB.Net中文教程(1) 類別與封裝性 (轉)封裝
- VB.Net中文教程(9) 重新定義(Overriding)程式 (轉)
- VB.Net中文教程(4) 類別繼承(Inheritance)關係 (轉)繼承
- 常用CSS樣式2:其它樣式CSS
- 走近VB.Net(二) 再談函式呼叫 (轉)函式
- 1.6 常用CSS樣式2:其它樣式CSS
- Word入門動畫教程142:應用樣式(轉)動畫
- Emacs 教程中文版(轉)Mac
- 走近VB.NET十六 SendKeys方法與Shell函式 (轉)函式
- ModernUI教程:如何從MUI樣式中派生自定義樣式UI
- [轉]Spring AOP中文教程Spring
- VB.NET聊天程式 (轉)
- 區域性神經(Composite) (轉)
- CSS-FONT樣式(轉)CSS
- CSS-COLOR樣式(轉)CSS
- jQuery 基礎樣式篇(2)jQuery
- 常用CSS樣式2:浮動CSS
- 精通ASP.NET(基於VB.NET)( 二)VB.NET類 (轉)ASP.NET
- composite
- 精通ASP.NET(基於VB.NET)(四)VB.NET繼承 (轉)ASP.NET繼承
- echarts圖表樣式轉換Echarts
- VB.NET中物件的克隆 (轉)物件
- JavaScript 基礎教程(2) (轉)JavaScript
- 中文web-app_2_3.dtd (轉)WebAPP
- CSS 第2個li元素樣式CSS
- 1.7 常用CSS樣式2:浮動CSS
- VB.NET中怎樣為listview繫結資料View
- 在VB.NET中尋找App (轉)APP
- XHTML+CSS:呼叫樣式表(轉)HTMLCSS
- GBK中文繁簡轉換函式函式
- 精通ASP.NET(基於VB.NET)( 三)VB.NET異常處理 (轉)ASP.NET
- VC++/MFC 教程2(英文) (轉)C++