VB.Net中文教程(11) Prototype樣式

來源:互聯網
上載者:User
教程|中文 主題: Prototype樣式
副題: 多型、介面(Interface)


????????? 內容 ?????????
v 1. 樣式
v 2. 對象之原型(object prototype)
v 3. 以VB落實Prototype樣式
v 4. Prototype樣式之應用----- 組件之設計與組裝


1. 樣式
Erich Gamma 等人的名著──"Design Patterns: Elements of Reusable Object-Oriented Software" 含有23個重要的設計樣式(design pattern)。顧名思義﹐「樣式」就是大家可「有樣學樣﹐依樣畫葫蘆」﹐並一而再、再而三地在不同場合﹐重複使用(reuse) 它來解決常見之問題。
樣式必須常常使用﹐且愈純熟愈好﹐才能隨外界環境(context) 而加以變化﹐才能確實解決問題(problem) 。像孫子兵法、太極拳法皆含有許多樣式(或稱為招式)﹐必須心領神會﹐並實際練習之﹐才能達到爐火純青之地步。其主要原因是﹕單一樣式(招式)常只解決個小問題﹐而大問題可能需要多種樣式混合使用才行。如何將小樣式組合成為大樣式來解決大問題呢﹖這常需一套完整的法則(rule)﹐通稱為「樣式語言」(pattern language)。本文引用Gamma書中的Prototype樣式﹐說明如何以VB的介面來實作之,也讓您更能善用多型觀念。以下就請您仔細看如何使用Prototype 樣式了。


圖1、Prototype樣式的UML圖


2. 對象之原型 (object prototype)
人們日常生活中﹐常見下述說法﹕

「我要養一隻像加菲貓一樣的貓」
「我將來要娶個美如西施的妻子」
......

其中﹐加菲貓和西施皆是prototype (或譯為範例)。當您說上述兩句話時﹐聽者立即能經由prototype 對象(即加菲貓或西施)來瞭解您心中所欲描述之新對象。在軟體方面﹐使用者可藉prototype 來告訴電腦﹕

「我要的對象就像這個prototype 對象」

於是﹐電腦依該prototype 對象來造出一模一樣的新對象給使用者。
回想﹐我們所熟悉的VB、C#、Java或C++語言中﹐皆是藉著「類別」來描述對象之特性﹐然後電腦則依類別之描述來造出新對象。這種就通稱為class-based programming ﹔而前者稱為prototype-based programming 。
隨著﹐軟體零組件(sofrware IC) 觀念的流行﹐prototype-based programming 觀念也愈來愈重要了。既使像VB語言﹐也能支援prototype-based programming 。


3. 以VB落實Prototype樣式
上圖1是Gamma書中所列出的prototype樣式。下圖2則是個實際的例子。


圖2、繪圖對象的Prototype

對象設計者從Shape衍生出Circle及Rectangle兩類別,並各誕生1個prototype對象,且存入ShapeList串列或數組之中。設計者必須為各類別定義Clone( )函式來誕生新對象,並構成多型。於是對象裝配者只需呼叫Clone( )函數就能獲得新對象,而不必具有類別觀念。未來,設計者可從Shape類別衍生出許許多多子類別,並把對象放入ShapeList中,供裝配者使用。
茲看看如何以VB來落實上圖2的UML模式:

'ex01.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-------------------------------------------------------------------------
Class Shape
Protected lx, ly As Integer
Public Sub SetXY(ByVal x As Integer, ByVal y As Integer)
lx = x
ly = y
End Sub
Public Overridable Sub Draw()
End Sub
Public Overridable Function Clone() As Shape
End Function
End Class

Class Circle
Inherits Shape

Public Overrides Sub Draw()
MessageBox.Show("Drawing a Circle at (" + str(lx) + ", " + str(ly) + ")")
End Sub
Public Overrides Function Clone() As Shape
Clone = New Circle()
End Function
End Class

Class Rectangle
Inherits Shape

Public Overrides Sub Draw()
MessageBox.Show("Drawing a Rectangle at (" + str(lx) + ", " + str(ly) + ")")
End Sub
Public Overrides Function Clone() As Shape
Clone = New Rectangle()
End Function
End Class
'-------------------------------------------------------------------------------------
Class ShapeList
Private tlist(10) As Shape
Private counter As Integer

Public Sub New()
counter = 0
End Sub
Public Sub AddShape(ByVal sobj As Shape)
tlist(counter) = sobj
counter = counter + 1
End Sub
Public Function GetShape(ByVal i As Integer) As Shape
GetShape = tlist(i)
End Function
Public Sub Draw()
Dim i As Integer
For i = 0 To counter - 1
tlist(i).Draw()
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 list As New ShapeList()
Dim ps As Shape
ps = New Circle()
ps.SetXY(10, 10)
list.AddShape(ps)

ps = New Rectangle()
ps.SetXY(50, 50)
list.AddShape(ps)

ps = list.GetShape(0).Clone()
ps.SetXY(230, 70)
list.AddShape(ps)

list.Draw()
End Sub
End Class

此程式輸出:
Draw a Circle at (10, 10)
Draw a Rectangle at (50, 50)
Draw a Circle at (230, 70)

ShapeList類別屬於Client,在設計ShapeList類別時,只能用到Shape類別的資訊而已;在Client(如上述的Form1類別)裡,除了誕生對象時使用到Circle和Rectangle類別名稱之外,也只能用到Shape類別的資訊而已;這讓我們未來能不斷擴充更多子類別,如Square、Triangle等等。為了達到此高度擴充性,需要用到多型(polymorphism)觀念。所以Shape類別裡建立了多形的基礎:

Public Overridable Sub Draw()
End Sub
Public Overridable Function Clone() As Shape
End Function
Draw( )和Clone( )皆是虛擬(virtual)程式,以發揮多型(polymorphism)功能。lx及ly是圖形的左上方座標。SetXY( )可改變lx及ly值。ShapeList類別的Draw程式用來繪出串列中的各prototype對象圖。
VB的父系類別(superclass)有兩種角色:
1) 提供一些程式給子類別繼承
2) 作為各子類別的共同介面(Interface)

上述程式是兩者合一的落實途徑。如果您落實到分布式(Distributed)環境裡,則宜將上述兩項角色分離並各別落實之。此時必須使用VB的Interface機制了。例如上述程式相當於:

'ex02.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'----------------------------------------------------
Interface IShape
Sub Draw()
Function Clone() As IShape
Sub SetXY(ByVal x As Integer, ByVal y As Integer)
End Interface

Class Shape
Protected lx, ly As Integer
Protected Sub SetXY(ByVal x As Integer, ByVal y As Integer)
lx = x
ly = y
End Sub
End Class

Class Circle
Implements IShape
Inherits Shape

Public Sub Draw() Implements IShape.Draw
MessageBox.Show("Drawing a Circle at (" + str(lx) + ", " + str(ly) + ")")
End Sub
Public Function Clone() As IShape Implements IShape.Clone
Clone = New Circle()
End Function
Public Sub SetValue(ByVal x As Integer, ByVal y As Integer) Implements IShape.SetXY
MyBase.SetXY(x, y)
End Sub
End Class

Class Rectangle
Inherits Shape
Implements IShape

Public Sub Draw() Implements IShape.Draw
MessageBox.Show("Drawing a Rectangle at (" + str(lx) + ", " + str(ly) + ")")
End Sub
Public Function Clone() As IShape Implements IShape.Clone
Clone = New Rectangle()
End Function
Public Sub SetValue(ByVal x As Integer, ByVal y As Integer) Implements IShape.SetXY
MyBase.SetXY(x, y)
End Sub
End Class
'------------------------------------------------------------------------------------------
Class ShapeList
Private tlist(10) As IShape
Private counter As Integer

Public Sub New()
counter = 0
End Sub
Public Sub AddShape(ByVal sobj As IShape)
tlist(counter) = sobj
counter = counter + 1
End Sub
Public Function GetShape(ByVal i As Integer) As IShape
GetShape = tlist(i)
End Function
Public Sub Draw()
Dim i As Integer
For i = 0 To counter - 1
tlist(i).Draw()
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 list As New ShapeList()
Dim pShape As IShape
pShape = New Circle()
pShape.SetXY(10, 10)
list.AddShape(pShape)

pShape = New Rectangle()
pShape.SetXY(50, 50)
list.AddShape(pShape)

pShape = list.GetShape(0).Clone()
pShape.SetXY(230, 70)
list.AddShape(pShape)

list.Draw()
End Sub
End Class

此程式輸出:
Draw a Circle at (10, 10)
Draw a Rectangle at (50, 50)
Draw a Circle at (230, 70)

Shape類別專心擔任幕后角色了,Client及ShapeList類別的設計者只看到IShape介面而已,這充分發揮了VB介面的優點。


4. Prototype樣式之應用
----- 組件之設計與組裝

軟體工業逐漸往零組件或稱組件(component) 方向發展﹐未來電腦軟體人員將分為兩大群﹕對象設計者(object designer) 與對象裝配者(object assembler)。就拿VB 程式員來說﹐對象設計者負責設計類別﹐以便誕生出各式各樣之對象﹔對象裝配者能使用現有對象或將之組裝成更大之對象或系統。
依據上述加菲貓和西施的例子中﹐人們常很自然地拿自己熟悉的例子來描述他所想要的對象﹔亦即經由舉例來說明他心中的對象﹐是較合乎人們生活習慣的。反而較少以類別來描述他心中之對象。因之﹐對象設計者定義好各類別之後也應各誕生一個對象﹐當做例子(prototype) ﹐最好顯示在Windows 畫面上。對象裝配者不需要具有「類別」觀念﹐只需用滑鼠點取畫面上的prototype 對象﹐就能獲得一個類似的新對象了。如此﹐就可構成美好的分工情形。然而﹐在VB及Java等語言中﹐對象皆是由「類別」來產生的。這會造成衝突問題﹕

u 設計者不能隨時誕生對象供裝配者使用﹐因而希望裝配者隨時藉由類別誕生對象。
u 裝配者最好不必具有類別觀念﹐因而不願意藉由類別來誕生對象。

如何化解這個問題呢﹖答案是﹕使用prototype 樣式。

對象設計者之工作包括:
1. 設計(定義)一個Form類別叫Form1。
2. 設計一個應用架構(application framework)做為「設計者」與「裝配者」分工的基礎。
3. 基於架構,衍生出子類別,如Circle及Rect。
4. 誕生對象,存入串列ShapList中,如圖3所示。


圖3、組裝的基礎環境

對象裝配者之工作是:
點取(或使訊息)給串列中的prototype對象,由其呼叫Clone( )來誕生新對象。
例如,讓「裝配者」自螢幕畫面上選取對象。Circle和Rectangle各定義Draw( )及Clone( )達到多型效果,讓「裝配者」使用起來更加方便。Clone( )必傳回一個新對象。Form1.Click()裡的指令-----

pShape = list.GetShape(0).Clone()
pShape.SetXY(230, 70)
list.AddShape(pShape)

首先,取出串列中的第0個prototype對象,此對象誕生另一個對象,由pShape代表之。在將此新對象存入串列中,如下圖所示:




圖4、組裝者依據prototype指示電腦誕生對象

最末將各prototype對象數示於畫面上。
上述例子中,把ShapeList也歸為對象設計者的掌管工作之一。在實際上,ShapeList常隸屬於「裝配工具」(assembly tools)內的一部份。而裝配工具的設計者,可能既非對象設計者,也非對象裝配者,而是用來協助「裝配者」使其工作效率更佳。
由於Clone函數及Draw( )程式的多型性,在加上Clone( )能產生新對象,使得裝配工具設計者,不必顧慮到物件類別之劇增,也不必用到期類別名稱,大大減少工具程式之複雜度,這也是prototype模式的另一個重要用途。■



相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。