前面学习了,以及,这些都是创建类的对象所使用的一些常用的方法和套路, 那么如果我们创建一个很复杂的对象可上面的三种方法都不太适合,那么“专业的事交给专业人去做”,23设计模式总有一个模式是适合这种复杂对象的创建。比如现在的智能手机组成, 它包括一个屏幕,摄像头,耳机接口,USB接口,CPU, RAM,主板等等, 但是每一个型号的手机的屏幕又不一样,有的是刘海的,有的是全屏的,有的是全面屏的,CUP 也不一样,有骁龙820 的,有 660的还有麒麟920 的等等,手机的组成图如下:
那么要创建一个这样的复杂对象, 该怎么创建呢? 那么该建造者模式闪亮登场了。
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。
它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是GetResult(),它们用于返回复杂对象。AbstractBuilder既可以是抽象类,也可以是接口。
它实现了AbstractBuilder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
负责安排复杂对象的建造次序,导演与抽象建造者之间存在关联关系,可以在其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(); } }
客户端调用:
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(); }
输出结果:
我们用本文开头提出的手组成的例子来挑选几个核心部件来构造几个型号的手机,使用建造者模式。
1、X1型手机:CUP 骁龙 835, RAM 6GB ,屏幕 刘海全屏, 硬盘 64GB。
2、X2 型手机: CUP 麒麟 930, RAM 8G, 屏幕 全面屏, 硬盘 128GB。
3、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>
输出结果:
好了建造者模式就探讨到这里。
如对本文有疑问, 点击进行留言回复!!
荐 厉害了!阿里P8架构师用4大技术文档带你深入解读爆火的中台战略
FlowableException: Error initialising dmn data model报错问题
网友评论