一、上篇回顧
上篇?jiǎng)?chuàng)建者模式中,我們主要講述了創(chuàng)建者的幾類實(shí)現(xiàn)方案,和創(chuàng)建者模式的應(yīng)用的場(chǎng)景和特點(diǎn),創(chuàng)建者模式適合創(chuàng)建復(fù)雜的對(duì)象,并且這些對(duì)象的每
個(gè)組成部分的詳細(xì)創(chuàng)建步驟可以是動(dòng)態(tài)的變化的,但是每個(gè)對(duì)象的組裝的過(guò)程來(lái)說(shuō)可能是相對(duì)固定的或者說(shuō)是對(duì)象的創(chuàng)建的過(guò)程是固定的,那么通過(guò)創(chuàng)建者
模式可以很好的解決這類復(fù)雜對(duì)象的創(chuàng)建,而在我們的生活中或者是項(xiàng)目中可能會(huì)有這個(gè)方面的需求,那么使用創(chuàng)建者模式無(wú)疑是好的選擇。
創(chuàng)建者模式中的每個(gè)對(duì)象組成部分的構(gòu)建都是對(duì)象本身提供的內(nèi)部方法,具體的創(chuàng)建者只是調(diào)用要?jiǎng)?chuàng)建的對(duì)象的內(nèi)部的相應(yīng)組成部分的構(gòu)建方法,組
織這些對(duì)象內(nèi)部構(gòu)建方法的執(zhí)行順序,完成對(duì)象的完整構(gòu)建。當(dāng)我們的客戶應(yīng)用程序需要調(diào)用這個(gè)創(chuàng)建者時(shí),我們只需要通過(guò)指導(dǎo)者調(diào)用的形式,提供統(tǒng)一
的創(chuàng)建者訪問(wèn)入口,通過(guò)構(gòu)造函數(shù)注入或者配置文件的形式來(lái)完成創(chuàng)建者的注入。
二、摘要
本文主要是講述創(chuàng)建型模式中一個(gè)比較特殊的模式-原型模式,這個(gè)模式呢,有個(gè)最大的特點(diǎn)是克隆一個(gè)現(xiàn)有的對(duì)象,這個(gè)克隆的結(jié)果有2種,一種是
是淺復(fù)制,另一種是深復(fù)制,這里我們也會(huì)探討下深復(fù)制和淺復(fù)制的原理,這樣可能更方便大家理解這個(gè)原型模式的使用。我們都知道,創(chuàng)建型模式一般是
用來(lái)創(chuàng)建一個(gè)新的對(duì)象,然后我們使用這個(gè)對(duì)象完成一些對(duì)象的操作,我們通過(guò)原型模式可以快速的創(chuàng)建一個(gè)對(duì)象而不需要提供專門(mén)的new()操作就可以快
速完成對(duì)象的創(chuàng)建,這無(wú)疑是一種非常有效的方式,快速的創(chuàng)建一個(gè)新的對(duì)象。本文將會(huì)從以下幾個(gè)方面進(jìn)行講述:
1、原型模式的使用場(chǎng)景和特點(diǎn)
2、淺復(fù)制和深復(fù)制的原理。
3、舉例說(shuō)明淺復(fù)制和深復(fù)制。
4、原型模式的實(shí)現(xiàn)方案。
5、總結(jié)原型模式。
我們這里先給出一個(gè)原型模式的原理圖:
三、本文大綱
a、上篇回顧。
b、摘要。
c、本文大綱。
d、原型模式的特點(diǎn)及使用場(chǎng)景。
e、深復(fù)制和淺復(fù)制。
f、原型模式的實(shí)現(xiàn)方案。
g、原型模式使用總結(jié)。
h、系列進(jìn)度。
i、下篇預(yù)告。
四、原型模式的特點(diǎn)及使用場(chǎng)景
原型模式的主要思想是基于現(xiàn)有的對(duì)象克隆一個(gè)新的對(duì)象出來(lái),一般是有對(duì)象的內(nèi)部提供克隆的方法,通過(guò)該方法返回一個(gè)對(duì)象的副本,這種創(chuàng)建對(duì)
象的方式,相比我們之前說(shuō)的幾類創(chuàng)建型模式還是有區(qū)別的,之前的講述的工廠模式與抽象工廠都是通過(guò)工廠封裝具體的new操作的過(guò)程,返回一個(gè)新的對(duì)
象,有的時(shí)候我們通過(guò)這樣的創(chuàng)建工廠創(chuàng)建對(duì)象不值得,特別是以下的幾個(gè)場(chǎng)景的時(shí)候,可能使用原型模式更簡(jiǎn)單也效率更高。
1、如果說(shuō)我們的對(duì)象類型不是剛開(kāi)始就能確定,而是這個(gè)類型是在運(yùn)行期確定的話,那么我們通過(guò)這個(gè)類型的對(duì)象克隆出一個(gè)新的類型更容易。這個(gè)
怎么理解。例如我們有的時(shí)候在處理DataTable中的記錄進(jìn)行篩選后,放在一個(gè)新的DataTable 中,我們知道如果說(shuō)2個(gè)dataTable的架構(gòu)不同,那么必須
手動(dòng)的顯示的賦值,否則無(wú)法使用如下方式進(jìn)行導(dǎo)入數(shù)據(jù):
下面給出測(cè)試的相關(guān)代碼和說(shuō)明
public class DataTableDemo
{
public void CloneTest()
{
string cmdText = “SELECT * FROM TABLE”;
DataTable dt = new DataTable();
//通過(guò)執(zhí)行上面的cmdText 返回一個(gè)dataTable對(duì)象;//這時(shí)候我們可以如下形式復(fù)制一個(gè)新的dataTable,而不用先創(chuàng)建一個(gè)dataTable,然后把每一列都顯示的循環(huán)添加到新的dataTable中,
//這是很大的工作量。
DataTable dt1 = dt.Clone();
//克隆一個(gè)新的對(duì)象 dt1.#region 不采用克隆的形式復(fù)制一個(gè)新的dataTable
DataTable dt2 = new DataTable();
foreach (DataColumn column in dt.Columns)
{
dt2.Columns.Add(column.ColumnName);
}#endregion
}
}2、有的時(shí)候我們可能在實(shí)際的項(xiàng)目中需要一個(gè)對(duì)象在某個(gè)狀態(tài)下的副本,這個(gè)前提很重要,這點(diǎn)怎么理解呢,例如有的時(shí)候我們需要對(duì)比一個(gè)對(duì)象經(jīng)
過(guò)處理后的狀態(tài)和處理前的狀態(tài)是否發(fā)生過(guò)改變,可能我們就需要在執(zhí)行某段處理之前,克隆這個(gè)對(duì)象此時(shí)狀態(tài)的副本,然后等執(zhí)行后的狀態(tài)進(jìn)行相應(yīng)的對(duì)
比,這樣的應(yīng)用在項(xiàng)目中也是經(jīng)常會(huì)出現(xiàn)的。
假設(shè)我們有這樣的需求,我們?cè)贠RM框架的設(shè)計(jì)中,經(jīng)常會(huì)遇到這樣的問(wèn)題,我們?cè)谔幚砟硞€(gè)對(duì)象的編輯狀態(tài)的時(shí)候,我們想框架給我們生成的更新
數(shù)據(jù)庫(kù)的SQL語(yǔ)句,不包含數(shù)據(jù)列沒(méi)有發(fā)生變化的列,不要出現(xiàn)在更新語(yǔ)句中,這個(gè)時(shí)候,可能一個(gè)方案會(huì)是,編輯前克隆一個(gè)對(duì)象,然后等編輯后提交
的時(shí)候,生成相應(yīng)的語(yǔ)句時(shí)進(jìn)行對(duì)比之前克隆的對(duì)象,看看是否數(shù)據(jù)發(fā)生變化,如果說(shuō)對(duì)象的部分?jǐn)?shù)據(jù)列發(fā)生變化,那么就只是把變化的數(shù)據(jù)列進(jìn)行更新。
當(dāng)然上面我只是給出了一種比較簡(jiǎn)單的,但是效率不是很高的實(shí)現(xiàn)方案,還有很多好的方案我就不討論了,這里只是為了說(shuō)明原型模式的可用場(chǎng)景。
如果對(duì)上面的方式不是很理解或者看文字比較累的話,可以看下面的圖,應(yīng)該就比較清晰了。
這就是這種情況下可能原型模式有比較好的表現(xiàn)。
3、當(dāng)我們?cè)谔幚硪恍?duì)象比較簡(jiǎn)單,并且對(duì)象之間的區(qū)別很小,可能只是很固定的幾個(gè)屬性不同的時(shí)候,可能我們使用原型模式更合適,例如我們生
活中的彩虹的七彩的顏色,等等,我們只需要根據(jù)現(xiàn)有的一個(gè)顏色對(duì)象,克隆一個(gè)新的顏色對(duì)象,然后修改具體的顏色的值就可以滿足要求,然后如果通過(guò)
我們之前講述的創(chuàng)建型工廠,抽象工廠模式等相對(duì)來(lái)說(shuō)就引入新的依賴,并且復(fù)雜度也有所提高。例如我們的生活中的顏色的克?。?/p>
我們都可以通過(guò)紅色來(lái)克隆其他的所有顏色,只是修改相應(yīng)的個(gè)別屬性即可,遠(yuǎn)比創(chuàng)建一個(gè)新的對(duì)
象,然后給對(duì)象的各個(gè)屬性賦值來(lái)的簡(jiǎn)單和方便,當(dāng)然有的時(shí)候,如果我們并不需要基于現(xiàn)有的對(duì)象復(fù)制新的對(duì)象,或者我們需要的就是一個(gè)干凈的空對(duì)
象,那么我的首先還是工廠模式或者抽象工廠模式啦。
五、深復(fù)制和淺復(fù)制
既然我們本篇講述了原型模式的具體應(yīng)用,那么我們就必須先搞清楚深復(fù)制和淺復(fù)制,否則也沒(méi)有辦清楚原型模式中的具體的克隆過(guò)程和克隆出來(lái)的
對(duì)象的詳細(xì)情況。
.NET Freamwork 內(nèi)置的每個(gè)繼承自System.Object都有保護(hù)成員方法:
//
// 摘要:
// 創(chuàng)建當(dāng)前 System.Object 的淺表副本。
//
// 返回結(jié)果:
// 當(dāng)前 System.Object 的淺表副本。
[SecuritySafeCritical]
protected object MemberwiseClone();系統(tǒng)為我們內(nèi)置提供了復(fù)制對(duì)象本身的方法,不過(guò)這個(gè)方法返回的是一個(gè)淺復(fù)制的對(duì)象副本,而且.NET給我提供了一個(gè)System.ICloneable的接口,
我們通過(guò)實(shí)現(xiàn)這個(gè)接口,可以為對(duì)象提供自定義的克隆方法。
為了搞明白淺復(fù)制和深復(fù)制,那么我先要搞懂這2者的區(qū)別,.NET本身提供了淺復(fù)制的方法,而深復(fù)制的方法需要自己實(shí)現(xiàn)接口來(lái)完成。
我們先來(lái)看看淺復(fù)制后的對(duì)象和對(duì)象副本的情況:
我們?cè)倏纯纯瓷顝?fù)制的對(duì)象和對(duì)象副本的情況:
通過(guò)上面的描述,大家應(yīng)該針對(duì)淺復(fù)制和深復(fù)制的區(qū)別有了大概的了解,那么我們?cè)俳Y(jié)合程序代碼來(lái)分
析吧,可能大家會(huì)更熟悉具體的應(yīng)用。我們先來(lái)看看最簡(jiǎn)單的淺復(fù)制和深復(fù)制情況,我們這里舉例來(lái)說(shuō)吧:
我們定義一個(gè)杯子類,并且簡(jiǎn)單定義杯子的幾項(xiàng)簡(jiǎn)單的屬性,具體代碼如下:
///
/// 杯子類
///
public class Cup : ICloneable
{
private double _rl;
private int _height;
private Factory _factory;
///
/// 高度
///
public int Height
{
get
{
return _height;
}
set
{
_height = value;
}
}///
/// 容量
///
public double RL
{
get
{
return _rl;
}
set
{
_rl = value;
}
}///
/// 生產(chǎn)廠家
///
public Factory Factory
{
get
{
return _factory;
}
set
{
_factory = value;
}
}#region ICloneable 成員
public object Clone()
{
return this.MemberwiseClone();
}#endregion
}具體的測(cè)試代碼:
class Program
{
static void Main(string[] args)
{
Cup cup = new Cup();
cup.Height = 2;
Cup cup1 = (Cup)cup.Clone();cup1.Height = 1;
Console.WriteLine(cup.Height == cup1.Height);
System.Threading.Thread.Sleep(10000);
}
}運(yùn)行結(jié)果如下:
綜上所述,我們知道,對(duì)于值類型的成員,淺復(fù)制也是在副本中重新創(chuàng)建的成員,對(duì)應(yīng)到內(nèi)存的棧上,分配新的內(nèi)存空間。那么對(duì)于引用類型則因?yàn)闇\復(fù)制
的時(shí)候,對(duì)象和對(duì)象副本共用同一個(gè)引用對(duì)象,那么不管是在對(duì)象還是對(duì)象副本中修改了相應(yīng)的引用成員了之后,那么這個(gè)引用類型的成員就會(huì)發(fā)生變化。
因?yàn)?個(gè)對(duì)象指向同一個(gè)內(nèi)存地址,那么任何一個(gè)修改操作都會(huì)產(chǎn)生改變。
那么對(duì)于上面的這個(gè)類如何修改這個(gè)類的實(shí)現(xiàn)才能實(shí)現(xiàn)深復(fù)制呢?
將上面的Clone方法如下實(shí)現(xiàn):
public object Clone()
{
Cup cup = (Cup)this.MemberwiseClone();
Factory factory1 = new Factory();
factory1.FactoryName = this.Factory.FactoryName;
cup.Factory = factory1;return cup;
}這樣就完成了對(duì)象的深復(fù)制,不管是值類型的成員還是引用類型的成員,這樣的對(duì)象和對(duì)象副本,對(duì)任何一個(gè)成員屬性的修改,都不會(huì)影響到改變對(duì)象的
值。
六、原型模式的實(shí)現(xiàn)方案
6.1 原型模式的經(jīng)典實(shí)現(xiàn)
我們先來(lái)看看原型模式的經(jīng)典實(shí)現(xiàn),我們這里已顏色為例來(lái)說(shuō)名下經(jīng)典實(shí)現(xiàn)吧
定義一個(gè)接口, 用來(lái)表述所有的顏色對(duì)象接口:
public interface IColorDemo
{
IColorDemo Clone();int Red
{
get;
set;
}
int Green
{
get;
set;
}
int Blue
{
get;
set;
}
}我們這里給出紅色的具體實(shí)現(xiàn)代碼:
public class RedColor : IColorDemo
{
private int red;
private int green;
private int blue;
public int Red
{
get
{
return this.red;
}
set
{
this.red = value;
}
}
public int Green
{
get
{
return this.green;
}
set
{
this.green = value;
}
}
public int Blue
{
get
{
return this.blue;
}
set
{
this.blue = value;
}
}#region IColorDemo 成員
public IColorDemo Clone()
{
return (IColorDemo)this.MemberwiseClone();
}#endregion
}因?yàn)樯厦娴膶?duì)于顏色,都是通過(guò)RGB不同的比例配置出來(lái)的,所以我就定義了3個(gè)整形的變量,所以我這里只是演示說(shuō)明。那么具體的測(cè)試代碼如下:
static void Main(string[] args)
{
IColorDemo color = new RedColor();
color.Red = 255;IColorDemo color1 = color.Clone();
color1.Blue = 255;Console.WriteLine(color.Blue == color1.Blue);
System.Threading.Thread.Sleep(10000);
}返回的結(jié)果為false。代表對(duì)象副本的修改不會(huì)影響對(duì)象本身的狀態(tài)。
6.2、原型模式的其他情況
上面講述了簡(jiǎn)單的淺復(fù)制的情況,那么我們來(lái)分析下深復(fù)制原型的實(shí)現(xiàn)吧,深復(fù)制可能考慮的情況相對(duì)來(lái)說(shuō)就會(huì)比較復(fù)雜,因?yàn)橛锌赡軐?duì)象是之間
有繼承關(guān)系或者引用關(guān)系的時(shí)候,可能我們深復(fù)制的時(shí)候就需要注意,當(dāng)然這對(duì)我們也是個(gè)考驗(yàn)。一般來(lái)說(shuō)深復(fù)制一方面可以采用上面我給出的那種簡(jiǎn)單的
深復(fù)制對(duì)象的時(shí)候的方案,還可以通過(guò)序列化的形式來(lái)進(jìn)行對(duì)象的復(fù)制。下面我們來(lái)通過(guò)序列化的形式來(lái)實(shí)現(xiàn)原型模式吧:
我們先給出序列化和反序列化的幫助類:
例如我們通過(guò)二進(jìn)制的形式來(lái)進(jìn)行序列化,我們都知道可以序列化的類必須打上標(biāo)記,標(biāo)識(shí)是否可以序列化,也可以在成員屬性上定義。
///
/// 序列化和反序列化輔助類
///
public class SerializableHelper
{
public string Serializable(object target)
{
using (MemoryStream stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, target);return Convert.ToBase64String(stream.ToArray());
}
}public object Derializable(string target)
{
byte[] targetArray = Convert.FromBase64String(target);using (MemoryStream stream = new MemoryStream(targetArray))
{
return new BinaryFormatter().Deserialize(stream);
}
}public T Derializable(string target)
{
return (T)Derializable(target);
}
}下面給出簡(jiǎn)單的示例代碼,還是使用上面的顏色對(duì)象為例。我們修改顏色類中的Clone方法
#region IColorDemo 成員
public IColorDemo Clone()
{
string target= SerializableHelper.Serializable(this);
return SerializableHelper.Derializable(target);
}#endregion
程序的測(cè)試代碼如下:
static void Main(string[] args)
{
IColorDemo color = new RedColor();
color.Red = 255;IColorDemo color1 = color.Clone();
color1.Red = 234;Console.WriteLine(color.Blue == color1.Blue);
System.Threading.Thread.Sleep(10000);
}程序的運(yùn)行結(jié)果為false,肯定二個(gè)對(duì)象是不同的,通過(guò)序列化和反序列化形成新的對(duì)象。其實(shí)只要是項(xiàng)目中要使用原型模式進(jìn)行對(duì)象復(fù)制的情況
下,都可以通過(guò)序列化的形式來(lái)進(jìn)行深復(fù)制。
七、原型模式使用總結(jié)
原型模式作為創(chuàng)建型模式中的最特殊的一個(gè)模式,具體的創(chuàng)建過(guò)程,是由對(duì)象本身提供,這樣我們?cè)诤芏嗟膱?chǎng)景下,我們可以很方便的快速的構(gòu)建新
的對(duì)象,就像前面分析講解的幾類場(chǎng)景中,可能我們通過(guò)使用對(duì)象的克隆,比通過(guò)其他幾類的創(chuàng)建型模式,效果要好的多,而且代價(jià)也小很多。打個(gè)比方,
原型模式對(duì)于系統(tǒng)的擴(kuò)展,可以做到無(wú)縫的擴(kuò)展,為什么這么說(shuō)呢?比如其他的創(chuàng)建型工廠,如果新增一個(gè)對(duì)象類型,那么我們不管是修改配置文件的方
式,還是修改代碼的形式,無(wú)疑我們都是需要進(jìn)行修改的,對(duì)于我們大家通用的公共應(yīng)用來(lái)說(shuō)這無(wú)疑是危險(xiǎn)的,那么通過(guò)原型模式,則可以解決這樣的問(wèn)
題,因?yàn)轭愋捅旧韺?shí)現(xiàn)這樣的方法即可,但是也有一定的缺點(diǎn),每個(gè)對(duì)象都實(shí)現(xiàn)這樣的方法,無(wú)疑是很大的工作量,但是在某些特殊的環(huán)境下,或者實(shí)際的
項(xiàng)目中,可能原型模式是好的選擇。
八、系列進(jìn)度
創(chuàng)建型
1、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-單件模式
2、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-工廠模式
3、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-抽象工廠模式
4、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-創(chuàng)建者模式
5、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-原型模式
結(jié)構(gòu)型
1、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-組合模式
2、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-外觀模式
3、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-適配器模式
4、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-橋模式
5、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-裝飾模式
6、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-享元模式
7、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-代理模式
行為型
1、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-命令模式
2、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-觀察者模式
3、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-策略模式
4、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-職責(zé)模式
5、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-模板模式
6、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-中介者模式
7、系統(tǒng)架構(gòu)技能之設(shè)計(jì)模式-解釋器模式
九、下篇預(yù)告
下篇將會(huì)針對(duì)外觀模式進(jìn)行講述,該模式也是結(jié)構(gòu)型模式中很有特點(diǎn)設(shè)計(jì)模式之一,該 模式是將現(xiàn)有系統(tǒng)中的一些細(xì)粒度的東西通過(guò)外觀對(duì)象包裝起來(lái),
在應(yīng)用程序中訪問(wèn)這些方法的時(shí)候,通過(guò)外觀類的形式,提供統(tǒng)一的訪問(wèn)入口,并且具體的細(xì)節(jié),應(yīng)用程序并不需要知道,這樣就會(huì)降低程序調(diào)用的復(fù)雜
性,由于本人水平有限,不足或者有錯(cuò)誤的地方,請(qǐng)大家批評(píng)指正,請(qǐng)大家繼續(xù)支持我,謝謝。
十、Demo下載
下載本文Demo文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-705372.html
轉(zhuǎn)自:https://www.cnblogs.com/hegezhou_hot/archive/2010/12/04/1896471.html文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-705372.html
到了這里,關(guān)于設(shè)計(jì)模式系列-原型模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!