|
本帖介紹 Prototype Pattern (原型模式),并以一個(gè)「人事招聘程序」作為示例來(lái)說(shuō)明。
--------------------------------------------------------
本帖的示例下載點(diǎn):
http://files.cnblogs.com/WizardWu/090713.zip
第一個(gè)示例為 Console Mode (控制臺(tái)應(yīng)用程序) 項(xiàng)目,第二個(gè)示例為 ASP.NET 網(wǎng)站項(xiàng)目。
執(zhí)行示例需要 Visual Studio 2008 或 IIS + .NET 3.0,不需要數(shù)據(jù)庫(kù)。
--------------------------------------------------------
Prototype Pattern (原型模式)
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
- Design Patterns: Elements of Reusable Object-Oriented Software
原型模式就是以一個(gè)既有的原型實(shí)例當(dāng)作范本,利用復(fù)制的方式,動(dòng)態(tài)獲得這個(gè)原型實(shí)例的狀態(tài)以及全部的字段和屬性,以此創(chuàng)建一或多個(gè)相同的對(duì)象,而且不需要知道任何創(chuàng)建的細(xì)節(jié)。
Prototype 模式打個(gè)通俗的比方:假如您在圖書(shū)館看到幾本自己喜歡的書(shū)籍,當(dāng)看到某些知識(shí)點(diǎn)時(shí),想在上面作相關(guān)記號(hào),但由于其是圖書(shū)館的書(shū),不能在上面亂涂亂畫(huà)。此時(shí)您只好把相關(guān)的章節(jié),用復(fù)印機(jī)把它復(fù)印出來(lái),然后在自己復(fù)印的紙張上作記號(hào)。在 Prototype Pattern 里,Clone 方法就如同此種復(fù)印的動(dòng)作,用戶從一個(gè)既有的原型實(shí)例 (如同圖書(shū)館里的書(shū)),復(fù)印后得到一或多個(gè)新的拷貝,不會(huì)破壞原本的原型,且用戶不必知道原型的內(nèi)容和格式。
Prototype 也具有一種「展示」的意味,就像是車(chē)展上的「原型」車(chē)款。當(dāng)您對(duì)某個(gè)車(chē)款感興趣時(shí),您可購(gòu)買(mǎi)相同的車(chē)款,而不是車(chē)展上展示的那輛車(chē)。
在軟件設(shè)計(jì)方面,也常需要進(jìn)行此種對(duì)象復(fù)制。例如我們要寫(xiě)一套室內(nèi)設(shè)計(jì)軟件,軟件的操作界面上有一條 Toolbar,用戶只要單擊 Toolbar 上的 Button,或用鼠標(biāo)拖曳到設(shè)計(jì)窗格中,就可創(chuàng)建一個(gè)桌子或椅子的副本,并可事后改變它的顏色或位置。當(dāng)設(shè)計(jì)師改變?cè)O(shè)計(jì)圖中的副本對(duì)象時(shí),Toolbar 上的「原型」對(duì)象并不會(huì)跟著被改變。同樣的觀念,亦適用于工業(yè)設(shè)計(jì) CAD 軟件、圖像處理軟件,以及 Visual Studio 等各種軟件的設(shè)計(jì)。
Prototype 模式的重點(diǎn)在于 Clone 方法,它負(fù)責(zé)復(fù)制 (克隆) 出一個(gè)新的對(duì)象并返回,而不是用 new 運(yùn)算符和某個(gè)類(lèi)的構(gòu)造函數(shù)去創(chuàng)建實(shí)例。在此模式中,派生類(lèi)如何覆寫(xiě)父類(lèi)的 Clone 方法將是重點(diǎn)。而 clone 的方式,又可分為「淺拷貝 (shallow copy)」和「深拷貝 (deep copy)」,在介紹這個(gè) Prototype 模式之前,先簡(jiǎn)單介紹一下這兩種拷貝方式的差異 [1], [2], [3], [4] :
- 淺拷貝; 淺表復(fù)制 (shallow copy):對(duì)象拷貝時(shí),如果字段是「值類(lèi)型 (Value Type)」,則直接復(fù)制其值 (亦即復(fù)制整個(gè)字段);若字段為「引用類(lèi)型 (Reference Type)」,則只復(fù)制其「引用 (reference; pointer)」,但不復(fù)制引用的字段,亦即若更改了任一個(gè)副本對(duì)象的某一個(gè)「引用類(lèi)型」字段,則原型正本對(duì)象、其他副本對(duì)象,也全部會(huì)一并更改 (如同本帖的第三個(gè)示例 02_Employee / 02_ShallowCopy_fail.ASPx.cs),也就是說(shuō)正本和所有的副本,都指向了內(nèi)存的同一個(gè)位置。
- 深拷貝; 深層復(fù)制 (deep copy):不論對(duì)象的字段為「值類(lèi)型」或「引用類(lèi)型」,都會(huì)完整地復(fù)制,而且這些字段和屬性都是完全獨(dú)立的。在深拷貝中,所有的對(duì)象都是重復(fù)的。
另補(bǔ)充,.NET 的類(lèi)型系統(tǒng),分為「值類(lèi)型」、「引用類(lèi)型」兩種,其對(duì)象在內(nèi)存中的存儲(chǔ)方式不同,如下:
- 值類(lèi)型:只需要一段單獨(dú)的內(nèi)存,用于存儲(chǔ)實(shí)際的數(shù)據(jù)在「棧 (Stack)」里,例如:int、byte、float、double、bool、struct、enum、char、...等類(lèi)型。
- 引用類(lèi)型:需要兩段內(nèi)存,第一段存儲(chǔ)實(shí)際的數(shù)據(jù),其總是位于「堆 (Heap)」中;第二段是一個(gè)存在「棧」里的引用 (reference; pointer),其指向數(shù)據(jù)在「堆」中的實(shí)際存放位置,例如:object、string、class (包括自定義類(lèi))、interface、delegate、array (參考本帖的第三、第四個(gè)示例) 等類(lèi)型。
但 string (字符串) 較特殊。string 雖然是「引用類(lèi)型」,但卻擁有「值類(lèi)型」的特性。在 Prototype Pattern 及本帖的四個(gè)示例中,當(dāng)透過(guò) MemberwiseClone 方法做「淺拷貝」時(shí),對(duì)象的 string 字段仍會(huì)被完整地復(fù)制,其結(jié)果就如同 int 等「值類(lèi)型」的字段一樣。
如下圖 1 及下方示例 01_Shell,我們可透過(guò)自定義的 Prototype 抽象類(lèi),搭配 .NET 最頂層基類(lèi) System.Object 的 MemberwiseClone 方法,達(dá)成對(duì)象的「淺拷貝」,亦即復(fù)制某個(gè)對(duì)象其所有「字段 (field)」的值;但在 .NET 中,亦可舍棄此一自定義抽象類(lèi),讓圖 1 中的 ConcretePrototype1 類(lèi)、ConcretePrototype2 類(lèi),改為實(shí)現(xiàn) .NET 原生的 System.ICloneable 接口,透過(guò)實(shí)現(xiàn)此接口唯一的一個(gè) Clone 方法,來(lái)達(dá)成對(duì)象的「淺拷貝」或「深拷貝」。
圖 1 此圖為 Prototype 模式的經(jīng)典類(lèi)圖

NET技術(shù):C# Design Patterns (5) - Prototype,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。