分享
 
 
 

VB.Net中文教程(2) Composite样式

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

请注意 ......

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

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)。再如﹐下图的Windows画面上﹐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)对象来表达之﹐如VB 的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.WinForms

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 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")

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.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有