C 設計模式03 原型模式

2021-07-09 22:18:00 字數 3253 閱讀 7594

好久沒有寫部落格了,因為過年實在太忙了,家裡也沒有網路,今天第一天上班就先寫一篇吧。話不多說,今天要寫的內容是:原型模式,它也是建立型模式中的一種

首先來看定義:使用原型例項指定待建立物件的型別,並且通過複製這個原型來 建立新的物件

理解定義之前先看一幅圖:

孫悟空可以變出很多個和自己一模一樣的猴子,這裡的孫悟空就是原型類,原型類裡面有乙個clone()方法可以複製他自己。有了這個方法他就可以自我複製出很多小猴子。原型模式和孫悟空自我複製自己這個模式差不多。

接下來我們就來看看原型模式的中的三種角色:

(1)prototype(抽象原型類):這個類宣告轉殖(複製)方法(也就是clone()方法),是所有具體原型類的父類,它可以是抽象類,介面或者具體的實現類

(2)concreteprototype(具體原型類):這個類實現(繼承)抽象原型類,實現(重寫)clone方法以返回自己的乙個轉殖物件

(3)client(客戶端類):這個類通過呼叫clone方法來轉殖物件,返回值為prototype

在介紹原型模式之前,有兩個概念需要解釋一下,也就是深轉殖(深複製)和淺轉殖(淺複製)。我們知道,c#中,值型別的資料存放在記憶體棧空間中,而引用型別存放在記憶體堆空間中,並且在棧空間上儲存了該物件的引用位址。執行淺轉殖操作時,會複製原型物件本身和原型物件中包含的值型別成員,而引用型別並沒有被複製,僅僅複製了引用型別的位址。對轉殖物件中引用型別的操作將直接影響原型物件。 而執行深轉殖操作時,不僅複製原型物件本身和原型物件中包含的值型別成員,而且會複製引用型別,所以對轉殖物件中引用型別的操作不會影響到原型型別。

c#中object型別的memberwiseclone方法可以幫助我們實現淺複製,而要想實現深複製的話,可以通過實現icloneable介面來手動建立當前物件的副本。

接下來我們先實現淺轉殖,因為它比較簡單。

假設現在有乙個客戶管理系統,有乙個客戶類customer,類裡面有name欄位表示客戶名稱,age欄位表示客戶年齡,還有乙個adress型別的成員變數表示客戶的位址。

現在通過原型模式來淺複製客戶類。

首先是我們的客戶位址adress類

namespace 原型模式

}

然後是我們的客戶類customer

namespace 原型模式

set

}private int age;

public int age

set

}public adress adress;

//使用memberwiseclone方法實現淺轉殖

public customer clone()}}

最後是我們的客戶端類

namespace 原型模式

; c.name = "曹瑞鵬";

c.adress = adress;

customer copy = c.clone();

console.writeline("客戶物件是否相同:",c==copy);

console.writeline("客戶年齡是否相同:", referenceequals(c.age, copy.age));

console.writeline("客戶姓名是否相同:", referenceequals(c.name, copy.name));

console.readline();}}

}

執行結果如下:

從執行結果上可以清楚的看到,客戶物件本身和客戶年齡這兩個變數都不相同了(也就是他們在記憶體中的位址不一致了)。而作為引用型別的位址和姓名這兩個變數在記憶體中的位址是相同的,所以引用型別並沒有被複製。這個就是淺複製。

object的referenceequals方法(靜態方法)用於測試兩個引用是否指向同乙個類的例項,也就是是否指向同乙個位址。

然後我們來實現深轉殖,深轉殖就是可以通過實現icloneable介面來手動實現轉殖

位址類adress和上面的一樣,客戶端類和客戶類需要修改一下

namespace 原型模式

set

}private int age;

public int age

set

}public adress adress;

public object clone()//深轉殖方法

;customer copy = this.memberwiseclone() as customer;

copy.adress = adress;

copy.name = "曹瑞鵬";

return copy;}}

}

namespace 原型模式

",c==copy);

console.writeline("客戶年齡是否相同:", referenceequals(c.age, copy.age));

console.writeline("客戶姓名是否相同:", referenceequals(c.name, copy.name));

console.readline();}}

}

執行結果如下:

從執行結果可以看得出來,客戶姓名和客戶位址都成了false,而在淺複製中他們的比較結果是true。這就說明深複製操作會複製引用型別。

除了可以通過實現icloneable介面達到深複製之外,還可以通過反射,序列化等方式實現深複製,有興趣的朋友可以自己去查閱相關文件資料或者書籍。 

優點:複製物件的代價遠小於建立物件的代價,所以當建立的物件較為複雜時,原型模式可以簡化物件的建立過程

缺點:每個類裡面必學有乙個clone轉殖方法,當對現有的類進行改造時,需要修改clone方法。這違背了開閉原則,擴充套件性也不是很好。同時深轉殖的實現會比較麻煩,因為當當前物件之間存在多重巢狀的時候,每一層物件都必須支援深轉殖。

原型型別的適用環境主要如下:

建立物件的成本較高,並且需要儲存物件的狀態資訊,而這些狀態資訊的變化比較小。

C 設計模式 原型模式

定義 用原型 prototype 例項指定建立物件的種類,並且通過拷貝這些原型建立新的物件。結構 理解 1.prototype 是原型基類,提供clone 純虛方法,它根據不同的派生類來轉殖不同的物件。2.concreteprototype 是原型具體類。實現clone 方法,轉殖自己,返回轉殖後的...

c 設計模式(原型模式)

good 從乙個物件再建立另外乙個可定製的物件,而無需知道任何建立的細節。並能提高建立的效能。說白了就copy技術,把乙個物件完整的copy出乙份。例 include include include using namespace std class prototype 抽象基類 prototype...

C 設計模式 原型模式

用原型例項指定建立物件的種類,並且通過拷貝這些原型建立新的物件。建立型模式中乙個比較特殊的模式 原型模式,有個最大的特點是轉殖乙個現有的物件,這個轉殖的結果有2種,一種是淺度複製,另一種是深度複製。建立型模式一般是用來建立乙個新的物件,然後我們使用這個物件完成一些物件的操作,我們通過原型模式可以快速...