?????? 這是解決一個復雜對象的創建工作,現在變化的部分和相對穩定的部分已經明確,我們要做的是隔離變化,如何將子對象和算法隔離是要解決的問題。
?????? 《設計模式》中說道:將一個復雜對象的構建與其表示向分離,使得同樣的構建過程可以創建不同的表示。
?????? 我們現在定義一個場景:還是選擇汽車, BMW 和 BORA 。試想一下,如果我們用較為普通的寫法可以寫成如下代碼:
public
static
void
??????? {
??????????? Car car = new Car();
??????????? Console.Write("Wheel:" + car._wheel + "\n");
??????????? Console.Write("OilBox:" + car._oilBox + "\n");
??????????? Console.Write("Body:" + car._body + "\n");
??????????? Console.Read();
??????? }
?
??????? public class Car
??????? {
??????????? public string _wheel = “ BMWWheel ” ;
??????????? public string _oilbox = “ BMWOilBox ” ;
??????????? public string _body = “ BMWBody ” ;
}
當我們不確定或因需求變化而改變對汽車品牌的選擇時,我們也許會頻繁的更改 Car 類中的實現。
現在我們用
Manager
來管理汽車的構建。當然是構建一個抽象的類對象(對象如下圖的
builder
,抽象類為
AbstractBuilder
)
,
對于
BMW
和
BORA
的構建類型繼承
AbstractBuilder
類
?
首先我們先來編寫
AbstractBuilder
抽象類的實現,代碼如下:
public abstract class AbstractBuilder
??? {
??????? public string _wheel;
??????? public string _oilBox;
??????? public string _body;
??????? public abstract void BuildWheel();
??????? public abstract void BuildOilBox();
??????? public abstract void BuildBody();
?
??????? public abstract Car GetCar();??
??? }
?
??? public abstract class Car
??? {
??? }
然后我們再來實現BMW和BORA的構建,也就是Builder模式中頻繁變化的部分,他們都要繼承AbstractBuilder
BMW :
public class BMWBuilder:AbstractBuilder
??? {
??????? public BMWBuilder()
??????? {
??????????? //
??????????? // TODO: 在此處添加構造函數邏輯
??????????? //
??????? }
?
??????? public override void BuildWheel()
??????? {
??????????? _wheel = "BMWWheel";
??????? }
?
??????? public override void BuildOilBox()
??????? {
??????????? _oilBox = "BMWOilBox";
??????? }
?
??????? public override void BuildBody()
??????? {
??????????? _body = "BMWBody";
??????? }
?
??????? public override Car GetCar()
??????? {
??????????? return new BMWCar();
??????? }
?
??? }
?
??? public class BMWCar:Car
??? {}
BORA :
public class BORABuilder:AbstractBuilder
??? {
??????? public BORABuilder()
??????? {
??????????? //
??????????? // TODO: 在此處添加構造函數邏輯
??????????? //
??????? }
?
??? ??? public override void BuildWheel()
??????? {
??????????? _wheel = "BORAWheel";
??????? }
?
??????? public override void BuildOilBox()
??????? {
??????????? _oilBox = "BORAOilBox";
??????? }
?
??????? public override void BuildBody()
??????? {
??????????? _body = "BORABody";
??????? }
?
??????? public override Car GetCar()
??????? {
??????????? return new BORACar();
??????? }
??? }
?
??? public class BORACar:Car
??? {}
現在我們使用一種Manager方法來管理汽車的構建,這也就是Builder模式中提到的相對穩定的算法,我用一個類來實現:
private class CarManager
??????? {
??????????? public BuilderClass.Car CreateCar(BuilderClass.AbstractBuilder builder)
??????????? {
??????????????? builder.BuildBody();
??????????????? builder.BuildOilBox();
??????????????? builder.BuildWheel();
?
??????????????? Console.Write("Wheel:" + builder._wheel + "\n");
??????????????? Console.Write("OilBox:" + builder._oilBox + "\n");
??????????????? Console.Write("Body:" + builder._body + "\n");
??????????????? Console.Read();
??????????????? return builder.GetCar();
??????????? }
??????? }
現在我們可以在客戶程序中調用這個Manager來構建Car:
public
static
void
??????? {
??????????? CarManager manager = new CarManager();
??????????? BuilderClass.Car car =
manager.CreateCar(new BuilderClass.BORABuilder());
??????? }
結果如下:
Wheel:BORAWheel
OilBox:BORAOilBox
Body:BORABody
如果我們現在要換成 BMW ,我們只要在 Main ()函數中改變 manager.CreateCar 中的參數就可以:
public
static
void
??????? {
??????????? CarManager manager = new CarManager();
??????????? BuilderClass.Car car = ?
manager.CreateCar(new BuilderClass.BMWBuilder());
??????? }
結果如下:
Wheel:BMWWheel
OilBox:BMWOilBox
Body:BMWBody
這樣,經過簡單的修改可以實現對不同 Car 的構建。如果我們還有其他汽車的實現只要將他的類繼承 AbstractBuilder ,然后在 Main ()中修改就可以。說道這里,我想起了在第一篇中提到的設計模式中的“開 --- 閉原則”,這個方式是很符合這個原則的,對代碼進行了擴展,以減少了代碼修改量。而且我們還有很多方法可以利用,如: WebConfig 中的 appSettings 來動態的配置,從數據庫中讀取,或利用依賴方式動態生成。
現在我們再來看看 Builder 模式的幾個要點:
Builder 模式主要用于構建一個復雜的對象,但這個對象構建的算法是穩定的,對象中的各個部分經常變化。 Builder 模式主要在于應對復雜對象各個部分的頻繁需求變動。但是難以應對算法的需求變動。這點一定要注意,如果用錯了,會帶來很多不必要的麻煩。
課程中還提到了 .Net 中的 Builder 模式的應用。如: Page 類中的 OnInit ()等方法的實現。我們在寫一個 Web 頁面的時候。他的 codebehind 代碼都是繼承 System.Web.UI.Page 基類的。 OnInit ()函數是可以重寫的