C#建造者模式
一、引言
它主要用於創建一些複雜對象,這些對象內部構建間的建造順序通常是穩定的,但對象內部的構建通常面臨着複雜的變化。
它使得建造代碼與表示代碼分離,由於建造者隱藏了該產品是如何組裝的,所以若需要改變一個產品的內部表示,只需要再定義一個具體的建造者就可以了。
二、目的
將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
三、特點
優點:
表述與構建分離。
方便擴展。
接口交互,建造者後期添加或減少不對用戶調用產生較大影響。
缺點:
建造者沒有等級的劃分,結構不清晰。
建造者內部的任務固定,順序不易顛倒,否則造成很大的影響
四、建造者範例
如上圖所示,
1、Director作統一調度和指揮,Director俗稱包“包工頭”;
2、Builder是建築的統一規範,它是抽象類。每個建築者必須繼承此類,以符合相關建築規範。
3、ConcreteBuilder是具體的建築隊,它繼承Builder,實現內部規範。
4、Product是產品,它是建築隊索要建造的對象。
包工頭,其職責在於指揮和控制建築隊
//指導員(包工頭),負責總指揮
class Director
{
//組建建築隊,不建議在這裏做,如果這樣做了,如果用戶想要改變建築隊,就需要修改Director類。耦合性高
//public Director()
//{
// Builder b1 = new ConcreteBuilder1(); //新建一個建築隊1
// Builder b2 = new ConcreteBuilder2(); //新建一個建築隊2
//}
//指揮一個"建築隊"做具體的事情。
public void Construct(Builder builder) //在包工頭職責裏含有指導指定建築隊進行相關作業
{
builder.BuildPartA(); //指揮建造A
builder.BuildPartB(); //指揮建造B
}
}
//按照情況來說,包公頭本應該還有一個職責就是召集若干個建築隊,但是這裏不建議
//建造者規範(此爲接口,Director與實際建造者溝通就是此接口)
//統一的接口,建築隊必須能造建築部分A,能早建築部分B,還可以反饋建造進度
abstract class Builder
{
public abstract void BuildPartA(); //建造A
public abstract void BuildPartB(); //建造B
public abstract Product GetResult();
}
//第一建築隊,符合建築規範的接口
class ConcreteBuilder1 : Builder
{
private Product product = new Product(); //有具體建築體
public override void BuildPartA()
{
product.Add("部件A");
}
public override void BuildPartB()
{
product.Add("部件B");
}
public override Product GetResult()
{
return product;
}
}
//第二建築隊,符合建築規範
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 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);
}
}
}
//用戶端
static void Main(string[] args)
{
Director director = new Director(); //新建一個指揮者(包工頭)
Builder b1 = new ConcreteBuilder1(); //新建一個建築隊1
Builder b2 = new ConcreteBuilder2(); //新建一個建築隊2
director.Construct(b1); //包工頭指揮建築隊1進行建造,調用相關函數
Product p1 = b1.GetResult(); //建築隊將建造的結果返回
p1.Show(); //顯示出建築1的細節
director.Construct(b2); //包工頭指揮建築隊2進行建造,調用相關函數
Product p2 = b2.GetResult(); //建築隊將建造的結果返回
p2.Show(); //顯示出建築2的細節
Console.Read();
}
五、程序分析
由上面的程序可知。用戶具有新建包工頭、新建建築隊的權利。可以最大程度放開權限。
並且,包工頭與建築隊直接唯一的連接點就是Builder對象。
director.Construct(b1); //b1爲實際建築隊
因爲Builder是抽象父類,根據里氏轉換原則來說。它可以接受所以繼承成Builer類的對象,這樣便實現了基於接口的編程。
無論後期的建築隊增加還是減少,都不影響Director指揮,因爲所有建築隊都是繼承Builder的。而建築隊本身完成的事情自然就是在抽象中Builder指定下完成的。
例如:
新建一個建築隊3
在ConsreteBuilder類中的後面添加一個新類
//第三建築隊,符合建築規範
class ConcreteBuilder3 : Builder
{
private Product product = new Product(); //有具體的建築體
public override void BuildPartA()
{
product.Add("部件M");
}
public override void BuildPartB()
{
product.Add("部件N");
}
public override Product GetResult()
{
return product;
}
}
//客戶端修改一下
static void Main(string[] args)
{
Director director = new Director(); //新建一個指揮者(包工頭)
Builder b1 = new ConcreteBuilder1(); //新建一個建築隊1
Builder b2 = new ConcreteBuilder2(); //新建一個建築隊2
Builder b3 = new ConcreteBuilder3(); //新建一個建築隊3
director.Construct(b1); //包工頭指揮建築隊1進行建造
Product p1 = b1.GetResult(); //建築隊將建造的結果返回
p1.Show(); //顯示出建築1的細節
director.Construct(b2); //包工頭指揮建築隊2進行建造
Product p2 = b2.GetResult(); //建築隊將建造的結果返回
p2.Show(); //顯示出建築2的細節
director.Construct(b3); //包工頭指揮建築隊2進行建造
Product p3 = b3.GetResult(); //建築隊將建造的結果返回
p3.Show(); //顯示出建築2的細節
Console.Read();
}
上述表明,新增一個建築隊,只要建築隊類中添加一個派生自Builder類新類。然後在客戶端這邊使用它即可。整個過程沒有對整體框架造成太大影響。
六、總結
建造者模式的關鍵點在於,通過一個包工頭類進行調度指定的建築隊做規範內的相同步驟和相同順序的事情。
什麼意思?
在包工頭內的Construct方法如下:
public void Construct(Builder builder)
{
builder.BuildPartA(); //指揮建造A,這是Builder規範內指定的方法1
builder.BuildPartB(); //指揮建造B,這是Builder規範內指定的方法2
}
這也就說明,
包工頭是調度指定的建築隊(builder參數接收)按照相同的順序(先BuilderPartA後BuilderPartB)進行建造。
所有的建築隊受包工頭的調度都會遵循這個順序和任務。
這邊引出了建造者模式的特點就是,調用不同的派生類做相同的事情。
具體關係圖如下: