設計模式-原型模式
參考資料
《c#技術揭密》
《設計模式-可複用物件導向軟體的基礎》
《java與模式》
http://blog.csdn.net/beautyispower/ ,很不錯的網友blog
很多餐館裡面都有菜單,列舉了他們提供哪些飯菜,哪種麵食等,一般的蘭州拉麵館裡菜單是這樣的
牛肉拉麵(大碗 )
牛肉拉麵(小碗)
牛肉刀削麵
羊肉拉麵
羊肉刀削麵
你到了這裡,你說我要吃手擀麵,我要吃挂面,我要吃珍珠翡翠鮑魚面,他恐怕沒有,這些面就需要定
制,上面說的牛肉拉麵,牛肉刀削麵等可以看作是原型,麵館可以看作是原型管理器。
原型模式在建立對象不是直接建立的,也就是說,不是通過外部調用類的建構函式調用的,而是通過
已存在的對象執行個體複製出一個對象,這個複製對象和他的來源物件具有相同的屬性和狀態,也就是說麵館裡的
牛肉刀削麵每一碗狀態都是一樣的。
複製對象分為淺拷貝和深拷貝
淺拷貝就是複製的對象和它的來源物件共用引用的對象,舉個例子,可能不恰當,假設牛肉刀削麵引用一個對象:Money,表示它值多少錢,這裡說的對象是說它是System.Object繼承的(c#), 也就是說不同的淺拷貝對象,他們的價錢是一樣的,當複製對象的價錢變過之後,它所引用的對象的價錢也就隨之改變了,比如麵館
調低了牛肉刀削麵的價格,由5塊錢調到了4塊錢,那麼每碗面的價格都變到了四塊錢。但對實值型別而言,每個淺拷貝對象都有自己的拷貝,也就是說,當改變複製對象的實值型別時,它的來源物件相應屬性不會改變。
深拷貝就是完全的拷貝
不僅實值型別有自己的拷貝,連引用對象也有自己的一份拷貝,修改複製對象的任何屬性,也不會對來源物件產生任何影響。
原型管理器,就是提供原型註冊使用,當建立對象使,可以使用裡面的對象進行複製,當有新的執行個體對象時,也可以將他們加到原型管理器裡。
說的有點亂,程式員,還是用代碼交流最好,下面的程式分別實現了原型複製時淺拷貝和深拷貝。
//
//理解深拷貝和淺拷貝
//
//淺表複本建立與原始對象具有相同類型的新執行個體,然後複製原始對象的非靜態欄位。
//如果欄位是實值型別的,則對該欄位執行逐位複製。如果欄位是參考型別,則複製該
//引用但不複製被引用的對象;這樣,原始對象中的引用和複本中的引用指向同一個對象。
//相反,對象的深層副本複製對象中欄位直接或間接引用的全部內容。
//
//例如,如果 X 是一個具有對對象 A 和對象 B 的引用的 Object,並且對象 A 還具
//有對對象 M 的引用,則 X 的淺表副本是對象 Y,而 Y 同樣具有對對象 A 和對象 B
//的引用。相反,X 的深層副本是對象 Y,而對象 Y 具有對對象 C 和對象 D 的直接引
//用以及對對象 N 的間接引用,其中 C 是 A 的副本,D 是 B 的副本,而 N 是 M 的副本。
using System;
using System.Collections;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Data;
namespace Prototype
{
/// <summary>
/// Prototype類型執行個體
/// </summary>
class TestPrototypeApp
{
/// <summary>
/// 應用程式的主進入點。
/// </summary>
[STAThread]
static void Main(string[] args)
{
//定義原型管理器
NoodleManager noodleManager=new NoodleManager();
//客戶要求下面三碗面
Noodle beefNoodle=(Noodle)noodleManager["牛肉拉麵"].Clone();
// Noodle beefNoodle=(Noodle)noodleManager["牛肉拉麵"].DeepClone();
Noodle muttonNoodle=(Noodle)noodleManager["羊肉拉麵"].Clone();
Noodle beefCutNoodle=(Noodle)noodleManager["牛肉刀削麵"].Clone();
//修改複製對象中的引用對象的屬性,驗證它是淺拷貝還是深拷貝
beefNoodle.TbName=",哈哈哈!,複製對象改名了,你改不改";
//顯示原始對象的NoodelName和TbName
Console.WriteLine(noodleManager["牛肉拉麵"].NoodleName+noodleManager["牛肉拉麵"].TbName+"/n");
//顯示複製對象的NoodleName和TbName
Console.WriteLine(beefNoodle.NoodleName+beefNoodle.TbName+"/n");
//將新的產品加入原型管理器,以備以後複製時使用,下面是定義了一種新的麵條-羊肉刀削麵,
//並把它添加到麵條管理器中,如果以後再有客戶點這個面,直接複製即可。
noodleManager["羊肉刀削麵"]=new CutNoodle("羊肉刀削麵");
//複製一碗羊肉刀削麵
Noodle muttonCutNoodle=(Noodle)noodleManager["羊肉刀削麵"].Clone();
Console.WriteLine(noodleManager["羊肉刀削麵"].NoodleName+"/n");
Console.WriteLine(muttonCutNoodle.NoodleName+"/n");
Console.ReadLine();
}
}
//抽象產品-麵條
//序列化屬性,為深拷貝時使用,每個衍生類別都要加上此屬性才能實現深拷貝
[Serializable]
public abstract class Noodle
{
//定義一個DataTable對象,主要是為了驗證對比類中含有引用對象時的深拷貝和淺拷貝時的不同,
//你也可以採用別的任何引用對象
protected DataTable dataTable=new DataTable();
public string TbName
{
get{return dataTable.TableName;}
set{dataTable.TableName=value;}
}
//欄位
protected string noodleName;
//特性
public string NoodleName
{
get{return noodleName;}
set{noodleName=value;}
}
public abstract Noodle Make(string name);
//淺複製的介面
public abstract Noodle Clone();
//深複製的介面
public abstract Noodle DeepClone();
}
//具體產品,拉麵
[Serializable]
public class PullNoodle:Noodle
{
public PullNoodle(string name)
{
this.NoodleName=name;
this.TbName=name+"table";
Console.WriteLine("PullNoodle is made/n");
}
//實現淺拷貝
public override Noodle Clone()
{
return (Noodle)this.MemberwiseClone();
}
//實現深拷貝,“淹鹹菜”的過程,先將對象序列化到記憶體流,再還原序列化,即可得到深複製
public override Noodle DeepClone()
{
//定義記憶體流
MemoryStream ms=new MemoryStream();
//定義二進位流
IFormatter bf=new BinaryFormatter();
//序列化
bf.Serialize(ms,this);
//重設指標到起始位置,以備還原序列化
ms.Position=0;
//返回還原序列化的深複製對象
return (Noodle)bf.Deserialize(ms);
}
public override Noodle Make(string name)
{
return new PullNoodle(name);
}
}
//具體產品-刀削麵
[Serializable]
public class CutNoodle:Noodle
{
public CutNoodle(string name)
{
this.NoodleName=name;
this.TbName=name+"table";
Console.WriteLine("CutNoodle is made/n");
}
//實現淺複製
public override Noodle Clone()
{
return (Noodle)this.MemberwiseClone();
}
public override Noodle Make(string name)
{
return new CutNoodle(name);
}
//實現深複製
public override Noodle DeepClone()
{
MemoryStream ms=new MemoryStream();
IFormatter bf=new BinaryFormatter();
bf.Serialize(ms,this);
ms.Position=0;
return (Noodle)bf.Deserialize(ms);
}
}
//定義原型管理器,用於儲存原型集合,這裡採用的是HashTable
class NoodleManager
{
//定義HashTable
protected Hashtable noodleHt=new Hashtable();
protected Noodle noodle;
public NoodleManager()
{
//初始化時加入三種基本原型
noodle=new PullNoodle("牛肉拉麵");
noodleHt.Add("牛肉拉麵",noodle);
noodle=new PullNoodle("羊肉拉麵");
noodleHt.Add("羊肉拉麵",noodle);
noodle=new CutNoodle("牛肉刀削麵");
noodleHt.Add("牛肉刀削麵",noodle);
}
//索引器,用於添加,訪問Noodle對象
public Noodle this[string key]
{
get{ return (Noodle)noodleHt[key];}
set{ noodleHt.Add(key,value);}
}
}
}