溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C#設(shè)計(jì)模式(6)——原型模式(Prototype Pattern)

發(fā)布時(shí)間:2020-06-12 21:54:00 來(lái)源:網(wǎng)絡(luò) 閱讀:2481 作者:LearningHard 欄目:編程語(yǔ)言

一、引言

在軟件系統(tǒng)中,當(dāng)創(chuàng)建一個(gè)類的實(shí)例的過(guò)程很昂貴或很復(fù)雜,并且我們需要?jiǎng)?chuàng)建多個(gè)這樣類的實(shí)例時(shí),如果我們用new操作符去創(chuàng)建這樣的類實(shí)例,這未免會(huì)增加創(chuàng)建類的復(fù)雜度和耗費(fèi)更多的內(nèi)存空間,因?yàn)檫@樣在內(nèi)存中分配了多個(gè)一樣的類實(shí)例對(duì)象,然后如果采用工廠模式來(lái)創(chuàng)建這樣的系統(tǒng)的話,隨著產(chǎn)品類的不斷增加,導(dǎo)致子類的數(shù)量不斷增多,反而增加了系統(tǒng)復(fù)雜程度,所以在這里使用工廠模式來(lái)封裝類創(chuàng)建過(guò)程并不合適,然而原型模式可以很好地解決這個(gè)問(wèn)題,因?yàn)槊總€(gè)類實(shí)例都是相同的,當(dāng)我們需要多個(gè)相同的類實(shí)例時(shí),沒(méi)必要每次都使用new運(yùn)算符去創(chuàng)建相同的類實(shí)例對(duì)象,此時(shí)我們一般思路就是想——只創(chuàng)建一個(gè)類實(shí)例對(duì)象,如果后面需要更多這樣的實(shí)例,可以通過(guò)對(duì)原來(lái)對(duì)象拷貝一份來(lái)完成創(chuàng)建,這樣在內(nèi)存中不需要?jiǎng)?chuàng)建多個(gè)相同的類實(shí)例,從而減少內(nèi)存的消耗和達(dá)到類實(shí)例的復(fù)用。 然而這個(gè)思路正是原型模式的實(shí)現(xiàn)方式。下面就具體介紹下設(shè)計(jì)模式中的原型設(shè)計(jì)模式。

二、原型模式的詳細(xì)介紹

在現(xiàn)實(shí)生活中,也有很多原型設(shè)計(jì)模式的例子,例如,細(xì)胞分裂的過(guò)程,一個(gè)細(xì)胞的有絲分裂產(chǎn)生兩個(gè)相同的細(xì)胞;還有西游記中孫悟空變出后孫的本領(lǐng)和火影忍者中鳴人的隱分身忍術(shù)等。下面就以孫悟空為例子來(lái)演示下原型模式的實(shí)現(xiàn)。具體的實(shí)現(xiàn)代碼如下:

///火影忍者中鳴人的影分身和孫悟空的的變都是原型模式
    class Client
    {
        static void Main(string[] args)
        {
            // 孫悟空 原型
            MonkeyKingPrototype prototypeMonkeyKing = new ConcretePrototype("MonkeyKing");
            // 變一個(gè)
            MonkeyKingPrototype cloneMonkeyKing = prototypeMonkeyKing.Clone() as ConcretePrototype;
            Console.WriteLine("Cloned1:\t"+cloneMonkeyKing.Id);
            // 變兩個(gè)
            MonkeyKingPrototype cloneMonkeyKing2 = prototypeMonkeyKing.Clone() as ConcretePrototype;
            Console.WriteLine("Cloned2:\t" + cloneMonkeyKing2.Id);
            Console.ReadLine();
        }
    }
    /// <summary>
    /// 孫悟空原型
    /// </summary>
    public  abstract class MonkeyKingPrototype
    {
        public string Id { get; set; }
        public MonkeyKingPrototype(string id)
        {
            this.Id = id;
        }
        // 克隆方法,即孫大圣說(shuō)“變”
        public abstract MonkeyKingPrototype Clone();
    }
    /// <summary>
    /// 創(chuàng)建具體原型
    /// </summary>
    public class ConcretePrototype : MonkeyKingPrototype
    {
        public ConcretePrototype(string id)
            : base(id)
        { }
        /// <summary>
        /// 淺拷貝
        /// </summary>
        /// <returns></returns>
        public override MonkeyKingPrototype Clone()
        {
            // 調(diào)用MemberwiseClone方法實(shí)現(xiàn)的是淺拷貝,另外還有深拷貝
            return (MonkeyKingPrototype)this.MemberwiseClone();
        }
    }

上面原型模式的運(yùn)行結(jié)果為(從運(yùn)行結(jié)果可以看出,創(chuàng)建的兩個(gè)拷貝對(duì)象的ID屬性都是與原型對(duì)象ID屬性一樣的):

C#設(shè)計(jì)模式(6)——原型模式(Prototype Pattern)

上面代碼實(shí)現(xiàn)的淺拷貝的方式,淺拷貝是指當(dāng)對(duì)象的字段值被拷貝時(shí),字段引用的對(duì)象不會(huì)被拷貝。例如,如果一個(gè)對(duì)象有一個(gè)指向字符串的字段,并且我們對(duì)該對(duì)象做了一個(gè)淺拷貝,那么這兩個(gè)對(duì)象將引用同一個(gè)字符串,而深拷貝是對(duì)對(duì)象實(shí)例中字段引用的對(duì)象也進(jìn)行拷貝,如果一個(gè)對(duì)象有一個(gè)指向字符串的字段,并且我們對(duì)該對(duì)象進(jìn)行了深拷貝的話,那么我們將創(chuàng)建一個(gè)對(duì)象和一個(gè)新的字符串,新的對(duì)象將引用新的字符串。也就是說(shuō),執(zhí)行深拷貝創(chuàng)建的新對(duì)象和原來(lái)對(duì)象不會(huì)共享任何東西,改變一個(gè)對(duì)象對(duì)另外一個(gè)對(duì)象沒(méi)有任何影響,而執(zhí)行淺拷貝創(chuàng)建的新對(duì)象與原來(lái)對(duì)象共享成員,改變一個(gè)對(duì)象,另外一個(gè)對(duì)象的成員也會(huì)改變。

介紹完原型模式的實(shí)現(xiàn)代碼之后,下面看下原型模式的類圖,通過(guò)類圖來(lái)理清原型模式實(shí)現(xiàn)中類之間的關(guān)系。具體類圖如下:

C#設(shè)計(jì)模式(6)——原型模式(Prototype Pattern)

三、原型模式的優(yōu)缺點(diǎn)

原型模式的優(yōu)點(diǎn)有:

  1. 原型模式向客戶隱藏了創(chuàng)建新實(shí)例的復(fù)雜性

  2. 原型模式允許動(dòng)態(tài)增加或較少產(chǎn)品類。

  3. 原型模式簡(jiǎn)化了實(shí)例的創(chuàng)建結(jié)構(gòu),工廠方法模式需要有一個(gè)與產(chǎn)品類等級(jí)結(jié)構(gòu)相同的等級(jí)結(jié)構(gòu),而原型模式不需要這樣。

  4. 產(chǎn)品類不需要事先確定產(chǎn)品的等級(jí)結(jié)構(gòu),因?yàn)樵湍J竭m用于任何的等級(jí)結(jié)構(gòu)

原型模式的缺點(diǎn)有:

  1. 每個(gè)類必須配備一個(gè)克隆方法

  2. 配備克隆方法需要對(duì)類的功能進(jìn)行通盤考慮,這對(duì)于全新的類不是很難,但對(duì)于已有的類不一定很容易,特別當(dāng)一個(gè)類引用不支持串行化的間接對(duì)象,或者引用含有循環(huán)結(jié)構(gòu)的時(shí)候。

四、.NET中原型模式的實(shí)現(xiàn)

在.NET中可以很容易地通過(guò)實(shí)現(xiàn)ICloneable接口(這個(gè)接口就是原型,提供克隆方法,相當(dāng)于與上面代碼中MonkeyKingPrototype抽象類)中Clone()方法來(lái)實(shí)現(xiàn)原型模式,如果我們想我們自定義的類具有克隆的功能,首先定義類繼承與ICloneable接口并實(shí)現(xiàn)Clone方法。在.NET中實(shí)現(xiàn)了原型模式的類如下圖所示(圖中只截取了部分,可以用Reflector反編譯工具進(jìn)行查看):

C#設(shè)計(jì)模式(6)——原型模式(Prototype Pattern)


五、總結(jié)

到這里關(guān)于原型模式的介紹就結(jié)束了,原型模式用一個(gè)原型對(duì)象來(lái)指明所要?jiǎng)?chuàng)建的對(duì)象類型,然后用復(fù)制這個(gè)原型對(duì)象的方法來(lái)創(chuàng)建出更多的同類型對(duì)象,它與工廠方法模式的實(shí)現(xiàn)非常相似,其中原型模式中的Clone方法就類似工廠方法模式中的工廠方法,只是工廠方法模式的工廠方法是通過(guò)new運(yùn)算符重新創(chuàng)建一個(gè)新的對(duì)象(相當(dāng)于原型模式的深拷貝實(shí)現(xiàn)),而原型模式是通過(guò)調(diào)用MemberwiseClone方法來(lái)對(duì)原來(lái)對(duì)象進(jìn)行拷貝,也就是復(fù)制,同時(shí)在原型模式優(yōu)點(diǎn)中也介紹了與工廠方法的區(qū)別(第三點(diǎn))。


附件:http://down.51cto.com/data/2363531
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI