原型模式(Prototype Pattern)

概述ide

在軟件系統中,有時候面臨的產品類是動態變化的,並且這個產品類具備必定的等級結構。這時若是用工廠模式,則與產品類等級結構平行的工廠方法類也要隨着這種變化而變化,顯然不大合適。那麼如何封裝這種動態的變化?從而使依賴於這些易變對象的客戶程序不隨着產品類變化?this

意圖設計

用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象。orm

結構圖對象

 

Prototype模式結構圖接口

生活中的例子開發

Prototype模式使用原型實例指定建立對象的種類。新產品的原型一般是先於所有產品創建的,這樣的原型是被動的,並不參與複製它本身。一個細胞的有絲分裂,產生兩個一樣的細胞,是一個扮演主動角色複製本身原型的例子,這演示了原型模式。一個細胞分裂,產生兩個一樣基因型的細胞。換句話說,細胞克隆了本身。get

 

使用細胞分裂例子的Prototype模式對象圖原型

原型模式解說string

咱們考慮這樣一個場景,假定咱們要開發一個調色板,用戶單擊調色板上任一個方塊,將會返回一個對應的顏色的實例,下面咱們看看如何經過原型模式來達到系統動態加載具體產品的目的。

很天然,咱們利用OO的思想,把每一種顏色做爲一個對象,併爲他們抽象出一個公用的父類,以下圖:

 

實現代碼:

public abstract class Color

{

        public abstract void Display();

}

public class RedColor:Color

{

    public override void Display()

    {

        Console.WriteLine("Red's RGB Values are:255,0,0");

    }

}

public class GreenColor:Color

{

    public override void Display()

    {

        Console.WriteLine("Green's RGB Values are:0,255,0");

    }

}

客戶程序須要某一種顏色的時候,只須要建立對應的具體類的實例就能夠了。可是這樣咱們並無達到封裝變化點的目的,也許你會說,可使用工廠方法模式,爲每個具體子類定義一個與其等級平行的工廠類,那麼好,看一下實現:

 


實現代碼:

public abstract class ColorFactory

{

    public abstract Color Create();

}

public class RedFactory:ColorFactory

{

    public override Color Create()

    {

        return new RedColor();

    }

}

public class GreenFactory:ColorFactory

{

    public override Color Create()

    {

        return new GreenColor();

    }

}

實現了這一步以後,能夠看到,客戶程序只要調用工廠方法就能夠了。彷佛咱們用工廠方法模式來解決是沒有問題的。可是,咱們考慮的僅僅是封裝了new變化,而沒有考慮顏色的數量是不斷變化的,甚至多是在程序運行的過程當中動態增長和減小的,那麼用這種方法實現,隨着顏色數量的不斷增長,子類的數量會迅速膨大,致使子類過多,顯然用工廠方法模式有些不大合適。

進一步思考,這些Color子類僅僅在初始化的顏色對象類別上有所不一樣。添加一個ColorTool這樣的類,來參數化的它的實例,而這些實例是由Color支持和建立的。咱們讓ColorTool經過克隆或者拷貝一個Color子類的實例來建立新的Color,這個實例就是一個原型。以下圖所示:

 

實現代碼:

abstract class ColorPrototype

{

    public abstract ColorPrototype Clone();

}

 

class ConcteteColorPrototype : ColorPrototype

{

 

    private int _red, _green, _blue;

 

 

    public ConcteteColorPrototype(int red, int green, int blue)

    {

        this._red = red;

        this._green = green;

        this._blue = blue;

    }

     public override ColorPrototype Clone()

    {

        //實現淺拷貝

        return (ColorPrototype) this.MemberwiseClone();

    }

 

    public void Display(string _colorname)

    {

        Console.WriteLine("{0}'s RGB Values are: {1},{2},{3}",

            _colorname,_red, _green, _blue );

    }

}

 

class ColorManager

    Hashtable colors = new Hashtable();

 

 

    public ColorPrototype this[string name]

    {

        get

        {

            return (ColorPrototype)colors[name];

        }

        set

        {

            colors.Add(name,value);

        }

    }

}

如今咱們分析一下,這樣帶來了什麼好處?首先從子類的數目上大大減小了,不須要再爲每一種具體的顏色產品而定一個類和與它等級平行的工廠方法類,而ColorTool則扮演了原型管理器的角色。再看一下爲客戶程序的實現:

class App

{

    public static void Main(string[] args)

    {

        ColorManager colormanager = new ColorManager();

 

        //初始化顏色

        colormanager["red"] = new ConcteteColorPrototype(255, 0, 0);

        colormanager["green"] = new ConcteteColorPrototype(0, 255, 0);

        colormanager["blue"] = new ConcteteColorPrototype(0, 0, 255);

        colormanager["angry"] = new ConcteteColorPrototype(255, 54, 0);

        colormanager["peace"] = new ConcteteColorPrototype(128, 211, 128);

        colormanager["flame"] = new ConcteteColorPrototype(211, 34, 20);

 

        //使用顏色

        string colorName = "red";

        ConcteteColorPrototype c1 = (ConcteteColorPrototype)colormanager[colorName].Clone();

        c1.Display(colorName);

 

        colorName = "peace";

        ConcteteColorPrototype c2 = (ConcteteColorPrototype)colormanager[colorName].Clone();

        c2.Display(colorName);

 

        colorName = "flame";

        ConcteteColorPrototype c3 = (ConcteteColorPrototype)colormanager[colorName].Clone();

        c3.Display(colorName);

 

        Console.ReadLine();

    }

}

能夠看到,客戶程序經過註冊原型實例就能夠將一個具體產品類併入到系統中,在運行時刻,能夠動態的創建和刪除原型。最後還要注意一點,在上面的例子中,用的是淺表複製。若是想作深複製,須要經過序列化的方式來實現。通過了上面的分析以後,咱們再來思考下面的問題:

1.爲何須要Prototype模式?

引入原型模式的本質在於利用已有的一個原型對象,快速的生成和原型對象同樣的實例。你有一個A的實例a:A a = new A();如今你想生成和car1同樣的一個實例b,按照原型模式,應該是這樣:A b = a.Clone();而不是從新再new一個A對象。經過上面這句話就能夠獲得一個和a同樣的實例,確切的說,應該是它們的數據成員是同樣的。Prototype模式一樣是返回了一個A對象而沒有使用new操做。

2.引入Prototype模式帶來了什麼好處?

能夠看到,引入Prototype模式後咱們再也不須要一個與具體產品等級結構平行的工廠方法類,減小了類的構造,同時客戶程序能夠在運行時刻創建和刪除原型。

3.Prototype模式知足了哪些面向對象的設計原則?

依賴倒置原則:上面的例子,原型管理器(ColorManager)僅僅依賴於抽象部分(ColorPrototype),而具體實現細節(ConcteteColorPrototype)則依賴與抽象部分(ColorPrototype),因此Prototype很好的知足了依賴倒置原則。

 

經過序列化實現深拷貝

要實現深拷貝,能夠經過序列化的方式。抽象類及具體類都必須標註爲可序列化的[Serializable],上面的例子加上深拷貝以後的完整程序以下:

using System;

using System.Collections;

using System.IO;

using System.Runtime.Serialization;

using System.Runtime.Serialization.Formatters.Binary;

 

[Serializable]

abstract class ColorPrototype

{

    public abstract ColorPrototype Clone(bool Deep);

}

 

[Serializable]

class ConcteteColorPrototype : ColorPrototype

{

 

    private int _red, _green, _blue;

 

 

    public ConcteteColorPrototype(int red, int green, int blue)

    {

        this._red = red;

        this._green = green;

        this._blue = blue;

    }

     public override ColorPrototype Clone(bool Deep)

    {

        if(Deep)

            return CreateDeepCopy();

        else

            return (ColorPrototype) this.MemberwiseClone();

    }

 

    //實現深拷貝

    public ColorPrototype CreateDeepCopy()

    {

        ColorPrototype colorPrototype;

 

        MemoryStream memoryStream = new MemoryStream();

        BinaryFormatter formatter = new BinaryFormatter();

 

        formatter.Serialize(memoryStream, this);

        memoryStream.Position = 0;

 

        colorPrototype = (ColorPrototype)formatter.Deserialize(memoryStream);

        return colorPrototype;

    }

 

    public ConcteteColorPrototype Create(int red,int green,int blue)

    {

        return new ConcteteColorPrototype(red,green,blue); 

    }

 

    public void Display(string _colorname)

    {

        Console.WriteLine("{0}'s RGB Values are: {1},{2},{3}",

            _colorname,_red, _green, _blue );

    }

}

 

class ColorManager

    Hashtable colors = new Hashtable();

     public ColorPrototype this[string name]

    {

        get

        {

            return (ColorPrototype)colors[name];

        }

        set

        {

            colors.Add(name,value);

        }

    }

}

 

 

class App

{

    public static void Main(string[] args)

    {

        ColorManager colormanager = new ColorManager();

 

        //初始化顏色

        colormanager["red"] = new ConcteteColorPrototype(255, 0, 0);

        colormanager["green"] = new ConcteteColorPrototype(0, 255, 0);

        colormanager["blue"] = new ConcteteColorPrototype(0, 0, 255);

        colormanager["angry"] = new ConcteteColorPrototype(255, 54, 0);

        colormanager["peace"] = new ConcteteColorPrototype(128, 211, 128);

        colormanager["flame"] = new ConcteteColorPrototype(211, 34, 20);

 

        //使用顏色

        string colorName = "red";

        ConcteteColorPrototype c1 = (ConcteteColorPrototype)colormanager[colorName].Clone(false);

        c1.Display(colorName);

 

        colorName = "peace";

        ConcteteColorPrototype c2 = (ConcteteColorPrototype)colormanager[colorName].Clone(true);

        c2.Display(colorName);

 

        colorName = "flame";

        ConcteteColorPrototype c3 = (ConcteteColorPrototype)colormanager[colorName].Clone(true);

        c3.Display(colorName);

 

        Console.ReadLine();

    }

}

 

實現要點

1.使用原型管理器,體如今一個系統中原型數目不固定時,能夠動態的建立和銷燬,如上面的舉的調色板的例子。

2.實現克隆操做,在.NET中可使用Object類的MemberwiseClone()方法來實現對象的淺表拷貝或經過序列化的方式來實現深拷貝。

3.Prototype模式一樣用於隔離類對象的使用者和具體類型(易變類)之間的耦合關係,它一樣要求這些「易變類」擁有穩定的接口。

效果

1.它對客戶隱藏了具體的產品類,所以減小了客戶知道的名字的數目。

2.Prototype模式容許客戶只經過註冊原型實例就能夠將一個具體產品類併入到系統中,客戶能夠在運行時刻創建和刪除原型。

3.減小了子類構造,Prototype模式是克隆一個原型而不是請求工廠方法建立一個,因此它不須要一個與具體產品類平行的Creater類層次。

4.Portotype模式具備給一個應用軟件動態加載新功能的能力。因爲Prototype的獨立性較高,能夠很容易動態加載新功能而不影響老系統。

5.產品類不須要非得有任何事先肯定的等級結構,由於Prototype模式適用於任何的等級結構

6.Prototype模式的最主要缺點就是每個類必須配備一個克隆方法。並且這個克隆方法須要對類的功能進行通盤考慮,這對全新的類來講不是很難,但對已有的類進行改造時,不必定是件容易的事。

適用性

在下列狀況下,應當使用Prototype模式:

1.當一個系統應該獨立於它的產品建立,構成和表示時;

2.當要實例化的類是在運行時刻指定時,例如,經過動態裝載;

3.爲了不建立一個與產品類層次平行的工廠類層次時;

4.當一個類的實例只能有幾個不一樣狀態組合中的一種時。創建相應數目的原型並克隆它們可能比每次用合適的狀態手工實例化該類更方便一些。

總結

Prototype模式同工廠模式,一樣對客戶隱藏了對象的建立工做,可是,與經過對一個類進行實例化來構造新對象不一樣的是,原型模式是經過拷貝一個現有對象生成新對象的,達到了「隔離類對象的使用者和具體類型(易變類)之間的耦合關係」的目的。

相關文章
相關標籤/搜索