一、建造者模式
將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
建造者模式的好處就是使得建造代碼與表示代碼分離,由於建造者隱藏了該產品是如何組裝的,所以若需要改變一個產品的內部表示,只需要再定義一個具體的建造者就可以了。
指揮者這個類用來控制建造過程,也用來隔離用戶與建造過程的關聯。
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; } }