建造者(Builder)模式
意图
建造者模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
比如:要创建一个对象分为三个步骤,第一,二,三步是同样的步骤,但是可以创建出不同的对象内容.
适用性
1).当创建复杂对象的算法应该独立于该对象的组成部分以及他们的装配方式时(创建对象的过程和对象的组成进行分离--->解耦)
2).当构造过程必须允许被构造的对象有不同表示时(同样的构造过程可以创建不同的对象)
对象性质的建造
有些情况下,一个对象会有一些重要的性质,在它们没有恰当的值之前,对象不能作为一个完整的产品使用。比如,一个电子邮件有发件人地址、收件人地址、主题、内容、附录等部分,而在最起码的收件人地址未被赋值之前,这个电子邮件不能发出。
有些情况下,一个对象的一些性质必须按照某个顺序赋值才有意义。在某个性质没有赋值之前,另一个性质则无法赋值。这些情况使得性质本身的建造涉及到复杂的商业逻辑。
这时候,此对象相当于一个有待建造的产品,而对象的这些性质相当于产品的零件,建造产品的过程就是组合零件的过程。由于组合零件的过程很复杂,因此,这些"零件"的组合过程往往被"外部化"到一个称作建造者的对象里,建造者返还给客户端的是一个全部零件都建造完毕的产品对象。
命名的考虑
之所以使用"建造者"而没有用"生成器"就是因为用零件生产产品,"建造"更为合适,"创建"或"生成"不太恰当。
建造者(Builder)角色:给出一个抽象接口,以规范产品对象(产品角色)的各个组成部件的建造。
具体建造者(Concrete Builder)角色:实现Builder接口,构造和装配产品的各个部件,定义并明确它所创建的表示.提供一个返回这个产品的接口.
指导者(Director)角色:构建一个使用Builder接口的对象.(连接产品角色和建造者之间的一个桥梁,通过指挥者指定哪个具体建造者去创建产品对象)
产品(Product)角色:产品便是被构建的复杂对象,具体建造者创建该产品的内部表示并定义它的装配过程.
包含定义组成部件的类,包括将这些部件装配成最终产品的接口.
ClassDiagram:
SequenceDiagram:
class BuilderPattern { public static void Main(String [] args) { /* 你是不是觉得指挥者(Director)是一个可有可无的角色,我们可以直接通过具体 的创建者(ConcreteBuilder)对象去调用部件:BuilderPartA(),BuilderPartB() 为什么要加一个Director呢? 实际上在加上Director之后,就对相应的创建者进行了一定程度上的封装,客户端就无需 知道这个产品到底是如何构建出来的它的步骤是怎么样子的,我们只需要知道调用之后 就把这个产品构建出来了,步骤我不需要关心.如果在客户端构建产品那么你必须知道它 的步骤是什么(它的第一步是什么,第二步是什么).所以指挥者角色指挥具体的建造者通过 什么样的步骤去创建相应的产品,通过这种方式我们的客户端就可以很透明的去创建产品. 这就是指挥者角色的作用.所以指挥者并不是一个可有可无的角色. */ Director director = new Director(); Builder b1 = new ConcreteBuilder1(); Builder b2 = new ConcreteBuilder2(); director.Construct(b1);//指挥者用ConcreteBuilder1的方法来创建产品 Product product1=b1.GetResult(); product1.Show(); Console.WriteLine("---------------------------------------------"); director.Construct(b2); Product product2 = b2.GetResult();//指挥者用ConcreteBuilder1的方法来创建产品 product2.Show(); Console.ReadKey(); } } /// <summary> /// 产品类,由多个部件组成. /// </summary> 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); } } } /// <summary> /// 抽象建造者类,确定产品由两个部件PartA和PartB组成, /// 并声明一个得到产品建造后结果的方法GetResult. /// </summary> abstract class Builder { public abstract void BuildPartA(); public abstract void BulidPartB(); public abstract Product GetResult(); } /// <summary> /// 具体创建的类 /// </summary> class ConcreteBuilder1:Builder { private Product product = new Product(); public override void BuildPartA() { product.Add("部件A"); } public override void BulidPartB() { product.Add("部件B"); } public override Product GetResult() { return product; } } /// <summary> /// 具体创建的类 /// </summary> class ConcreteBuilder2 : Builder { Product product = new Product(); public override void BuildPartA() { product.Add("部件X"); } public override void BulidPartB() { product.Add("部件Y"); } public override Product GetResult() { return product; } } /// <summary> /// 指挥者类 /// </summary> class Director { /// <summary> /// 用来指挥创建过程 /// </summary> public void Construct(Builder builder) { builder.BuildPartA(); builder.BulidPartB(); } }
客户端负责创建指导者和具体建造者对象。然后,客户端把具体建造者对象交给指导者。客户一声令下,指导者操纵建造者开始创建产品。当产品创建完成后,建造者把产品返还给客户端。
/// <summary> /// 下面的程序代码演示了Shop对象使用VehicleBuilders来建造不同的交通工具。 /// 该例子使用了Builder模式顺序建造交通工具的不同部分。 /// </summary> class BuilderApp { public static void Main(String[] args) { Shop shop = new Shop(); MotorCycleBuilder MotorCycle = new MotorCycleBuilder(); shop.Construct(MotorCycle); MotorCycle.Vehicle.Show(); CarBuilder Car = new CarBuilder(); shop.Construct(Car); Car.Vehicle.Show(); ScooterBuilder Scooter = new ScooterBuilder(); shop.Construct(Scooter); Scooter.Vehicle.Show(); Console.ReadKey(); } } /// <summary> /// 产品类Product /// </summary> class Vehicle { private String type; private Hashtable parts = new Hashtable(); public Vehicle(String type) { this.type = type; } //索引器Indexers public object this[String key] { get { return parts[key]; } set {parts[key]=value;} } public void Show() { Console.WriteLine("-----------------------"); Console.WriteLine("Vehicle Type:"+type);//类型 Console.WriteLine("Frame:"+parts["frame"]);//框架 Console.WriteLine("Engine:"+parts["engine"]);//引擎 Console.WriteLine("Wheels:"+parts["wheels"]);//轮子 Console.WriteLine("Doors:" + parts["doors"]);//仓门 } } /// <summary> /// 建造者Bulider(放置产品的具体构建逻辑) /// </summary> abstract class VehicleBuilder { protected Vehicle vehicle; public Vehicle Vehicle { get { return vehicle; } } abstract public void BuildFrame(); abstract public void BuildEngine(); abstract public void BuildWheels(); abstract public void BuildDoors(); } /// <summary> /// Director 指挥者 /// </summary> class Shop { public void Construct(VehicleBuilder vehicleBuilder) { vehicleBuilder.BuildFrame(); vehicleBuilder.BuildEngine(); vehicleBuilder.BuildWheels(); vehicleBuilder.BuildDoors(); } } /// <summary> /// 具体的建造者类:摩托车 /// </summary> class MotorCycleBuilder:VehicleBuilder { public override void BuildFrame() { vehicle = new Vehicle("MotorCycle"); vehicle["frame"] = "MotorCycleFrame"; } public override void BuildEngine() { vehicle["engine"]="500cc"; } public override void BuildWheels() { vehicle["wheels"] = "2"; } public override void BuildDoors() { vehicle["doors"] = "0"; } } /// <summary> /// 具体的建造者类:汽车 /// </summary> class CarBuilder : VehicleBuilder { // Methods override public void BuildFrame() { vehicle = new Vehicle("Car"); vehicle["frame"] = "Car Frame"; } override public void BuildEngine() { vehicle["engine"] = "2500 cc"; } override public void BuildWheels() { vehicle["wheels"] = "4"; } override public void BuildDoors() { vehicle["doors"] = "4"; } } /// <summary> /// 具体的建造者类:电动车 /// </summary> class ScooterBuilder : VehicleBuilder { // Methods override public void BuildFrame() { vehicle = new Vehicle("Scooter"); vehicle["frame"] = "Scooter Frame"; } override public void BuildEngine() { vehicle["engine"] = "none"; } override public void BuildWheels() { vehicle["wheels"] = "2"; } override public void BuildDoors() { vehicle["doors"] = "0"; } }
建造者模式的演化
省略抽象建造者角色
如果系统中只需要一个具体建造者的话,可以省略掉抽象建造者。这时代码可能如下:
// "Director" class Director { private ConcreteBuilder builder; // Methods public void Construct() { builder.BuildPartA(); builder.BuildPartB(); } }
省略指导者角色
在具体建造者只有一个的情况下,如果抽象建造者角色已经被省略掉,那么还可以省略掉指导者角色。让Builder角色自己扮演指导者与建造者双重角色。这时代码可能如下:
public class Builder { private Product product = new Product(); public void BuildPartA() { //Some code here } public void BuildPartB() { //Some code here } public Product GetResult() { return product; } public void Construct() { BuildPartA(); BuildPartB(); } }
同时,客户端也需要进行相应的调整,如下:
public class Client { private static Builder builder; public static void Main() { builder = new Builder(); builder.Construct(); Product product = builder.GetResult(); } }