一、建造者模式
將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
建造者模式的好處就是使得建造代碼與表示代碼分離,由於建造者隱藏了該產品是如何組裝的,所以若需要改變一個產品的內部表示,只需要再定義一個具體的建造者就可以了。
指揮者這個類用來控制建造過程,也用來隔離用戶與建造過程的關聯。
Builder:人
ConcreteBuilder1:胖子
ConcreteBuilder2:瘦子
Director:開始組裝
Product:成果
//具體產品類,最終形成的產品樣式 class Product { //產品的組成部分的集合 IList<string> parts = new List<string>(); //增加部件 public void Add(string part) { parts.Add(part); } //列舉所有的產品部件 public void Show() { Console.WriteLine("\n產品 創建 ----"); foreach (string part in parts) { Console.WriteLine(part); } } }
//抽象建造者類,確定有幾個部件,並返回產品 abstract class Builder { //兩個部件組成 public abstract void BuildPartA(); public abstract void BuildPartB(); public abstract Product GetResult(); } //產品A實現類 class ConcreteBuilder1 : Builder { private Product product = new Product(); //將部件A組裝到產品上 public override void BuildPartA() { product.Add("部件A"); } //將部件B組裝到產品上 public override void BuildPartB() { product.Add("部件B"); } public override Product GetResult() { return product; } } //產品B實現類 class ConcreteBuilder2 : Builder { private Product product = new Product(); public override void BuildPartA() { product.Add("部件X"); } public override void BuildPartB() { product.Add("部件Y"); } public override Product GetResult() { return product; } }
//指揮者類 class Director { public void Construct(Builder builder) { //創建部件A builder.BuildPartA(); //創建部件B builder.BuildPartB(); } }
//客戶端代碼 static void Main(string[] args) { //初始化一個指揮者 Director director = new Director(); //初始化兩個具體產品類 Builder b1 = new ConcreteBuilder1(); Builder b2 = new ConcreteBuilder2(); //創建產品A director.Construct(b1); //獲得最終產品 Product p1 = b1.GetResult(); p1.Show(); //創建產品B director.Construct(b2); //獲得最終產品 Product p2 = b2.GetResult(); p2.Show(); Console.Read(); }
二、原型模式
用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。
原型模式其實就是從一個對象再創建另外一個可定制的對象,而且不需要知道任何創建的細節。
一般在初始化的信息不發生變化的情況下,克隆是最好的辦法,這樣既隱藏了對象創建的細節,又對性能是大大的提高,不用重新初始化對象,而是動態地獲得對象運行時的狀態。
//抽象原型類 abstract class Prototype { private string id; // 構造函數
public Prototype(string id) { this.id = id; } // 屬性 public string Id { get { return id; } } public abstract Prototype Clone(); } //具體原型類1 class ConcretePrototype1 : Prototype { public ConcretePrototype1(string id): base(id) { } //創建當前對象的淺表副本 public override Prototype Clone() { return (Prototype)this.MemberwiseClone(); } } //也可以通過實現NET提供的ICloneable接口來取代抽象類 class ConcretePrototype2 : ICloneable {
private string id; // 構造函數
public ConcretePrototype2 (string id) { this.id = id; }
public string Id
{
get { return id; }
}
public Object Clone() { return (Object)this.MemberwiseClone(); } }
//客戶端代碼 static void Main(string[] args) { //創建p1 ConcretePrototype1 p1 = new ConcretePrototype1("I"); //復制給c1 ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone(); Console.WriteLine("Cloned: {0}", c1.Id); ConcretePrototype2 p2 = new ConcretePrototype2("II"); ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone(); Console.WriteLine("Cloned: {0}", c2.Id); // Wait for user Console.Read(); }
淺表復制(MemberwiseClone()):如果字段是值類型的,則對該字段執行逐位復制;如果字段是引用類型,則復制引用但不復制引用的對象;因此,原始對象及其復本引用同一對象。
深復制:把引用對象的變量指向復制過的新對象,而不是原有的被引用的對象。如果需要深復制,需要在復制方法中編寫程序,把任何形式類型轉換成值類型再復制一次。
三、單例模式
保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
所有類都有構造方法,不編碼則系統默認生成空的構造方法,若有顯式定義的構造方法,默認的構造方法就會失效,將構造方法的修飾符改為private,則外部程序就不能用new來實例化它了。
優勢:讓類自身復制保持它的唯一實例。這個類可以保證沒有其他實例可以被創建,並且還提供了一個訪問該實例的方法(對唯一的實例可以嚴格地控制用戶怎樣及何時訪問它)。
//Singleton類 class Singleton { private static Singleton instance; private static readonly object syncRoot = new object(); //修改構造方法修飾符,使外界不能利用new創建實例 private Singleton() { } //創建實例 public static Singleton GetInstance() { //雙重鎖定,先判斷實例是否存在,不存在再加鎖處理 if (instance == null) { //不存在,則加線程鎖,防止其他線程在前一個線程沒有執行完的時候再次創建 lock (syncRoot) { if (instance == null) { //初始化實例 instance = new Singleton(); } } } return instance; } }
//客戶端代碼 static void Main(string[] args) { //用此方法初始化實例
Singleton s1 = Singleton.GetInstance();
//由於s1已經創建了實例,則s2不會再次創建新實例
Singleton s2 = Singleton.GetInstance(); if (s1 == s2) { Console.WriteLine("Objects are the same instance"); } Console.Read(); }
PS:lock是確保當一個線程位於代碼的臨界區時,另一個線程不進入臨界區。如果其他線程試圖進入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。
四、衍生
靜態初始化:c#與公共語言運行庫提供了一種“靜態初始化”方法,這種方法不需要開發人員顯式地編寫線程安全代碼,即可解決多線程環境下它是不安全的問題。
餓漢式單例類:靜態初始化的方式是在自己被加載時就將自己實例化。一般已經足夠使用
懶漢式單例類:在第一次被引用時,才會將自己實例化。
//增加sealed修飾符,阻止發生派生,而派生可能會增加實例 public sealed class Singleton { //在第一次引用類的任何成員時創建實例 private static readonly Singleton instance = new Singleton(); private Singleton() { } public static Singleton GetInstance() { return instance; } }