一、适用场景以及优缺点
1.适用场景
1)当创建复杂对象的算法应该独立于该对象的组成 部分,以及他们的装配方式时。
2)相同的方法,不同的顺序,产生不同的事件结果时。
3)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不同时。
4)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能。
5)创建一些复杂的对象时,这些对象的内部组件间的建造顺序是稳定的,但是对象的内部组件面临着复杂的变化。
类似于:在现实生活中,我们经常会遇到一些构成比较复杂的物品,比如:电脑,它就是一个复杂的物品,它主要是由CPU、主板、硬盘、显卡、机箱等组装而成的。</br>
手机当然也是复杂物品,由主板,各种芯片,RAM 和ROM 摄像头之类的东西组成。但是无论是电脑还 是手机,他们的组装过程是固定的,就拿手机来说,
组装流水线是固定的,不变的,但是把不同的主板和其他组件组装在一起就会生产出不同型号的手机。
2.优点
1)使用建造者模式可以使客户端不必知道产品内部组成的细节。
2)具体的建造者类之间是相互独立的,容易扩展。
3)由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。
3.缺点
产生多余的Build对象以及Dirextor(指导者)类。
二、动机以及组成部分
动机:
在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,
但是将它们组合在一起的算法却相对稳定。
组成部分:
1)抽象建造者角色(Builder):创建一个抽象接口,此角色规定要实现复杂对象的那些部分的创建,却不涉及具体的对象部件的创建。
2)具体建造者:实现Builder的接口 以构造和装配该产品的各个部件,也就是实现抽象建造者角色Builder的方法。
定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各部分的创建。
提供一个检索产品的接口。
构造一个使用Builder接口的对象即在指导者的调用下创建产品实例。
3)指导者(Dirextor):调用具体建造者角色以创建产品对象的各个部分。指导者并没有涉及具体产品类的信息,真正拥有具体产品的信息是具体建造者对象。
它只负责保证对象各部分完整创建或按照某种顺序创建。
4)产品角色(Product):建造中的复杂对象。它要包含那些定义组件的类,包括这些组件装配成产品的接口。
代码:
Director director = new Director(); Builder buickCarBuilder = new BuickBuilder(); Builder aoDiCarBuilder = new AoDiBuilder(); director.Construct(buickCarBuilder); //组装完成,我来驾驶别克了 Car1 buickCar = buickCarBuilder.GetCar(); buickCar.Show(); // 我老婆就要奥迪了,她比较喜欢大品牌 director.Construct(aoDiCarBuilder); Car1 aoDiCar = aoDiCarBuilder.GetCar(); aoDiCar.Show();
/// <summary> /// 这个类型才是组装的,Construct方法里面的实现就是创建复杂对象固定算法的实现,该算法是固定的,或者说是相对稳定的 /// 这个人当然就是老板了,也就是建造者模式中的指挥者 /// </summary> public class Director { // 组装汽车 public void Construct(Builder builder) { builder.BuildCarDoor(); builder.BuildCarWheel(); builder.BuildCarEngine(); } // 组装新汽车(无轮子) public void ConstructNew(Builder builder) { builder.BuildCarDoor(); builder.BuildCarEngine(); } } /// <summary> /// 汽车类 /// </summary> public sealed class Car1 { // 汽车部件集合 private IList<string> parts = new List<string>(); // 把单个部件添加到汽车部件集合中 public void Add(string part) { parts.Add(part); } public void Show() { Console.WriteLine("汽车开始在组装......."); foreach (string part in parts) { Console.WriteLine("组件" + part + "已装好"); } Console.WriteLine("汽车组装好了"); } } /// <summary> /// 抽象建造者,它定义了要创建什么部件和最后创建的结果,但是不是组装的的类型,切记 /// </summary> public abstract class Builder { // 创建车门 public abstract void BuildCarDoor(); // 创建车轮 public abstract void BuildCarWheel(); //创建车引擎 public abstract void BuildCarEngine(); // 当然还有部件,大灯、方向盘等,这里就省略了 // 获得组装好的汽车 public abstract Car1 GetCar(); } /// <summary> /// 具体创建者,具体的车型的创建者,例如:别克 /// </summary> public sealed class BuickBuilder : Builder { Car1 buickCar = new Car1(); public override void BuildCarDoor() { buickCar.Add("Buick's Door"); } public override void BuildCarWheel() { buickCar.Add("Buick's Wheel"); } public override void BuildCarEngine() { buickCar.Add("Buick's Engine"); } public override Car1 GetCar() { return buickCar; } } /// <summary> /// 具体创建者,具体的车型的创建者,例如:奥迪 /// </summary> public sealed class AoDiBuilder : Builder { Car1 aoDiCar = new Car1(); public override void BuildCarDoor() { aoDiCar.Add("Aodi's Door"); } public override void BuildCarWheel() { aoDiCar.Add("Aodi's Wheel"); } public override void BuildCarEngine() { aoDiCar.Add("Aodi's Engine"); } public override Car1 GetCar() { return aoDiCar; } }
在微软的类库里面大量使用了设计模式,如果要想学习设计模式,仔细看看微软的类库是很有帮助的。 今天的设计模式在FCL里面也有实现,该类型的名字就是System.Text.StringBuilder(存在mscorlib.dll程序集中),它就是一个建造者模式的实现,从名称也可以看出 来。不过它的实现属于建造者模式的演化,此时的建造者模式没有指挥者角色和抽象建造者角色,StringBuilder类即扮演着具体建造者的角色,也同时扮演了指挥者和抽象建造者的角色,StringBuilder类扮演着建造string对象的具体建造者角色,其中的ToString()方法用来返回具体产品给客户端(相当于上面代码中GetProduct方法)。其中Append方法用来创建产品的组件(相当于上面代码中BuildPartA和BuildPartB方法),因为string对象中每个组件都是字符,所以也就不需要指挥者的角色的代码(指的是Construct方法,用来调用创建每个组件的方法来完成整个产品的组装),因为string字符串对象中每个组件都是一样的,都是字符,所以Append方法也充当了指挥者Construct方法的作用。