前面學習了簡單工廠模式,工廠方法模式以及抽象工廠模式,這些都是建立類的對象所使用的一些經常使用的方法和套路, 那麼若是咱們建立一個很複雜的對象可上面的三種方法都不太適合,那麼「專業的事交給專業人去作」,23設計模式總有一個模式是適合這種複雜對象的建立。好比如今的智能手機組成, 它包括一個屏幕,攝像頭,耳機接口,USB接口,CPU, RAM,主板等等, 可是每個型號的手機的屏幕又不同,有的是劉海的,有的是全屏的,有的是全面屏的,CUP 也不同,有驍龍820 的,有 660的還有麒麟920 的等等,手機的組成圖以下:html
那麼要建立一個這樣的複雜對象, 該怎麼建立呢? 那麼該建造者模式閃亮登場了。編程
建造者模式(Builder Pattern):將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。建造者模式是一種對象建立型模式。設計模式
它爲建立一個產品Product對象的各個部件指定抽象接口,在該接口中通常聲明兩類方法,一類方法是buildPartX(),它們用於建立複雜對象的各個部件;另外一類方法是GetResult(),它們用於返回複雜對象。AbstractBuilder既能夠是抽象類,也能夠是接口。app
它實現了AbstractBuilder接口,實現各個部件的具體構造和裝配方法,定義並明確它所建立的複雜對象,也能夠提供一個方法返回建立好的複雜產品對象。ide
它是被構建的複雜對象,包含多個組成部件,具體建造者建立該產品的內部表示並定義它的裝配過程。函數
負責安排複雜對象的建造次序,導演與抽象建造者之間存在關聯關係,能夠在其Construct()建造方法中調用建造者對象的部件構造與裝配方法,完成複雜對象的建造。客戶端通常只須要與指揮者進行交互,在客戶端肯定具體建造者的類型,並實例化具體建造者對象(也能夠經過配置文件和反射機制),而後經過指揮者類的構造函數將該對象傳入指揮者類中。學習
public class Product { public string PartA { get; set; } public string PartB { get; set; } public string PartC { get; set; } } public abstract class AbstractBuilder { protected Product product = new Product(); public abstract void BuildPartA(); public abstract void BuildPartB(); public abstract void BuildPartC(); public Product GetResult() { return product; } } public class ConreteBuilder : AbstractBuilder { public override void BuildPartA() { this.product.PartA = "PartA"; } public override void BuildPartB() { this.product.PartB = "PartB"; } public override void BuildPartC() { this.product.PartC = "PartC"; } } public class Director { private AbstractBuilder builder; public Director(AbstractBuilder builder) { this.builder = builder; } public Product Construct() { builder.BuildPartA(); builder.BuildPartB(); builder.BuildPartC(); return builder.GetResult(); } }
客戶端調用:ui
static void Main(string[] args) { AbstractBuilder builder = new ConreteBuilder(); Director director = new Director(builder); Product product = director.Construct(); Console.WriteLine(product.PartA); Console.WriteLine(product.PartB); Console.WriteLine(product.PartC); Console.ReadKey(); }
輸出結果:this
咱們用本文開頭提出的手組成的例子來挑選幾個核心部件來構造幾個型號的手機,使用建造者模式。spa
一、X1型手機:CUP 驍龍 835, RAM 6GB ,屏幕 劉海全屏, 硬盤 64GB。
二、X2 型手機: CUP 麒麟 930, RAM 8G, 屏幕 全面屏, 硬盤 128GB。
三、X3型手機: CPU 驍龍 960 RAM 10G,屏幕 超清全面屏 256GB。
UML 圖以下:
代碼:
public class Mobile { public string CPU { get; set; } public string Screen { get; set; } public string RAM { get; set; } public string Disk { get; set; } } public abstract class MobileBuilder { protected Mobile mobile = new Mobile(); public abstract void BuildCPU(); public abstract void BuildScreen(); public abstract void BuildRAM(); public abstract void BuildDisk(); public Mobile GetMobile() { return this.mobile; } } public class X1Builder:MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X1]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X1]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X1]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X1]:Disk had been built."; } } public class X2Builder:MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X2]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X2]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X2]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X2]:Disk had been built."; } } public class X3Builder:MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X3]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X3]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X3]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X3]:Disk had been built."; } } public class MobileDirector { private MobileBuilder builder; public MobileDirector(MobileBuilder builder) { this.builder=builder; } public Mobile GetMobile(){ this.builder.BuildCPU(); this.builder.BuildRAM(); this.builder.BuildScreen(); this.builder.BuildDisk(); return this.builder.GetMobile(); } }
調用代碼以下:
static void Main(string[] args) { MobileBuilder builder=new X1Builder(); MobileDirector mobileDrector = new MobileDirector(builder); Mobile mobile = mobileDrector.GetMobile(); Console.WriteLine(mobile.CPU); Console.WriteLine(mobile.Screen); Console.WriteLine(mobile.RAM); Console.WriteLine(mobile.Disk); Console.ReadKey(); }
輸出結果:
若是想生產X2型號的手機,只須要將具體建造者代碼修改一下就能夠了,即將下面的一行代碼:
MobileBuilder builder=new X1Builder();
改爲:
MobileBuilder builder=new X2Builder();
輸出結果:
也能夠將具體建造者類配置在配置文件中,經過反射來建立建造者對象進而建立出新的型號的手機。
在配置文件中加入以下配置:
<appSettings> <add key="Builder" value="DesignPattern.Builder.MobileInstance.X3Builder"/> </appSettings>
客戶端調用代碼以下:
static void Main(string[] args) { MobileBuilder builder; var setting = ConfigurationSettings.AppSettings["Builder"]; var obj = Type.GetType(setting); if (obj == null) return; builder = Activator.CreateInstance(obj) as MobileBuilder; if (builder == null) return; MobileDirector mobileDrector = new MobileDirector(builder); Mobile mobile = mobileDrector.GetMobile(); Console.WriteLine(mobile.CPU); Console.WriteLine(mobile.Screen); Console.WriteLine(mobile.RAM); Console.WriteLine(mobile.Disk); Console.ReadKey(); }
輸出結果:
Director在建造者模式中扮演着重要的角色,Director類看似簡單可是做用卻很是大,它決定複雜對象各個部分的建立順序而且將構建對象的過程和具體建造者隔離,好比建立一個房子,首先確定要作的事情是打地基,而後是磊牆,而後是封頂,最後是裝修,這個過程是有順序的且必須是這個順序,其它過程不沒法完成房子的建造。
Director'就好像是拍電影導演同樣,導演要拍一部電影,須要拍攝若干影像片斷,最後由剪輯師作剪接拼接,導演最後會進行最終的剪輯排版合成一個長片-- 電影。那麼電影就充當了建造者模式中的複雜產品,拍攝的影像片斷就是產片的各個部分,剪輯就是建造者模式的具體具體建造者,劇本是建造者模式的抽象建造者,導演就是Director。那麼在在這個過程當中,編劇是不能夠兼任導演? 剪輯師是否是也能夠兼任導演呢?答案是確定的。
那上面手機建造的實例,刪除掉Diretor, 將建立複雜對象的邏輯放到抽象建造者中,而且使子類方法不能重寫父類中的建造產品的方法,引用以前的配置代碼演變成以下:
public class Mobile { public string CPU { get; set; } public string Screen { get; set; } public string RAM { get; set; } public string Disk { get; set; } } public abstract class MobileBuilder { protected Mobile mobile = new Mobile(); public abstract void BuildCPU(); public abstract void BuildScreen(); public abstract void BuildRAM(); public abstract void BuildDisk(); public static Mobile GetMobile(MobileBuilder builder) { builder.BuildCPU(); builder.BuildScreen(); builder.BuildRAM(); builder.BuildDisk(); return builder.mobile; } } public class X1Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X1]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X1]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X1]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X1]:Disk had been built."; } } public class X2Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X2]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X2]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X2]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X2]:Disk had been built."; } } public class X3Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X3]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X3]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X3]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X3]:Disk had been built."; } }
調用代碼:
static void Main(string[] args) { MobileBuilder builder; var setting = ConfigurationSettings.AppSettings["Builder"]; var obj = Type.GetType(setting); if (obj == null) return; builder = Activator.CreateInstance(obj) as MobileBuilder; if (builder == null) return; Mobile mobile = builder.GetMobile(); Console.WriteLine(mobile.CPU); Console.WriteLine(mobile.Screen); Console.WriteLine(mobile.RAM); Console.WriteLine(mobile.Disk); Console.ReadKey(); }
輸出結果:
這種在抽象建造者中使用了一個靜態方法來建立產品的作法的好處是產品建立出來的一致性很好,建立產品流程被統一封裝,通常不會有差別,這種方式抽象類控制了產品建造的順序,而且全部的產品的建立順序都不能改變了(如造房子的流程),對於要求建立順序一致,而且產品部件的建立都路程一致的產品來講這是一個優勢。
可是若是想建立出來的產品有差別,每個產品的順序都不同那該怎麼辦呢?好比如今這種方法建立出來的順序是: CPU=》Screen=》RAM=》Disk, 那麼我要想X3型號的手機建立順序變成:CPU=》RAM=》Disk=》Screen。 這種方法就顯得不靈活了,沒有辦法作到個性化了。處理典型的將建造過程的控制權交給Director外,還能夠不用Director來完成嗎?
這裏咱們依然刪掉Director, 將抽象方法中的建立方法變成子類能夠重寫的虛方法就能夠了,而後在具體建造者中重寫抽象建造者的建立方法就能夠了。
如今咱們建立X1,X2,X3型號的手機的順序分別是這樣的:
X1: CPU=》Screen=》RAM=》Disk
X2:CPU=》RAM=》Disk=》Screen
X3:CPU=》Disk=》RAM=》Screen
代碼以下:
public class Mobile { public string CPU { get; set; } public string Screen { get; set; } public string RAM { get; set; } public string Disk { get; set; } } public abstract class MobileBuilder { protected Mobile mobile = new Mobile(); public abstract void BuildCPU(); public abstract void BuildScreen(); public abstract void BuildRAM(); public abstract void BuildDisk(); public virtual Mobile GetMobile() { this.BuildCPU(); this.BuildScreen(); this.BuildRAM(); this.BuildDisk(); Console.WriteLine(mobile.CPU); Console.WriteLine(mobile.Screen); Console.WriteLine(mobile.RAM); Console.WriteLine(mobile.Disk); return this.mobile; } } public class X1Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X1]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X1]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X1]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X1]:Disk had been built."; } } public class X2Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X2]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X2]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X2]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X2]:Disk had been built."; } public override Mobile GetMobile() { BuildCPU(); BuildRAM(); BuildDisk(); BuildScreen(); Console.WriteLine(mobile.CPU); Console.WriteLine(mobile.RAM); Console.WriteLine(mobile.Disk); Console.WriteLine(mobile.Screen); return this.mobile; } } public class X3Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X3]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X3]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X3]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X3]:Disk had been built."; } public override Mobile GetMobile() { BuildCPU(); BuildDisk(); BuildRAM(); BuildScreen(); Console.WriteLine(mobile.CPU); Console.WriteLine(mobile.Disk); Console.WriteLine(mobile.RAM); Console.WriteLine(mobile.Screen); return this.mobile; } }
調用代碼:
static void Main(string[] args) { MobileBuilder builder; var setting = ConfigurationSettings.AppSettings["Builder"]; var obj = Type.GetType(setting); if (obj == null) return; builder = Activator.CreateInstance(obj) as MobileBuilder; if (builder == null) return; Mobile mobile = builder.GetMobile(); Console.ReadKey(); }
輸出結果:
假如要造一個X4型號的手機,這個手機支持NFC,咱們知道X1,X2,X3中都不支持NFC,那怎麼辦呢?,咱們能夠給抽象建造者類加一個方法,叫 HasNFC()而且返回bool值,並將其設置成默認值爲false。 修改抽象建造者的GetMobile() 方法,只有當HasNFC()返回 true是才建立NFC模塊,而且在X4Builder的具體建造者類中重寫HasNFC()方法使其返回true就能夠了。
代碼以下:
public class Mobile { public string CPU { get; set; } public string Screen { get; set; } public string RAM { get; set; } public string Disk { get; set; } } public abstract class MobileBuilder { protected Mobile mobile = new Mobile(); public abstract void BuildCPU(); public abstract void BuildScreen(); public abstract void BuildRAM(); public abstract void BuildDisk(); public virtual void BuildNFC() { Console.WriteLine("NFC had been built."); } protected virtual bool HasNFC() { return false; } public virtual Mobile GetMobile() { this.BuildCPU(); this.BuildScreen(); this.BuildRAM(); this.BuildDisk(); if(HasNFC()) { this.BuildNFC(); } Console.WriteLine(mobile.CPU); Console.WriteLine(mobile.Screen); Console.WriteLine(mobile.RAM); Console.WriteLine(mobile.Disk); return this.mobile; } } public class X1Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X1]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X1]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X1]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X1]:Disk had been built."; } } public class X2Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X2]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X2]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X2]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X2]:Disk had been built."; } public override Mobile GetMobile() { BuildCPU(); BuildRAM(); BuildDisk(); BuildScreen(); Console.WriteLine(mobile.CPU); Console.WriteLine(mobile.RAM); Console.WriteLine(mobile.Disk); Console.WriteLine(mobile.Screen); return this.mobile; } } public class X3Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X3]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X3]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X3]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X3]:Disk had been built."; } public override Mobile GetMobile() { BuildCPU(); BuildDisk(); BuildRAM(); BuildScreen(); Console.WriteLine(mobile.CPU); Console.WriteLine(mobile.Disk); Console.WriteLine(mobile.RAM); Console.WriteLine(mobile.Screen); return this.mobile; } } public class X4Builder : MobileBuilder { public override void BuildCPU() { mobile.CPU = "[X4]:CPU had been built."; } public override void BuildScreen() { mobile.Screen = "[X4]:Screen had been built."; } public override void BuildRAM() { mobile.RAM = "[X4]:RAM had been built."; } public override void BuildDisk() { mobile.Disk = "[X4]:Disk had been built."; } protected override bool HasNFC() { return true; } }
App.Config 配置:
<appSettings> <add key="Builder" value="DesignPattern.Builder.MobileInstance.X3Builder"/> </appSettings>
客戶端代碼:
static void Main(string[] args) { MobileBuilder builder; var setting = ConfigurationSettings.AppSettings["Builder"]; var obj = Type.GetType(setting); if (obj == null) return; builder = Activator.CreateInstance(obj) as MobileBuilder; if (builder == null) return; Mobile mobile = builder.GetMobile(); Console.ReadKey(); }
輸出結果:
修改配置文件,使其造一臺X4 以下,調用代碼不變:
<appSettings> <add key="Builder" value="DesignPattern.Builder.MobileInstance.X4Builder"/> </appSettings>
輸出結果:
好了建造者模式就探討到這裏。