建造者模式将一个复杂的对象的构建与它的表示分离,使得一样的构建过程能够建立不一样的表示。建立者模式隐藏了复杂对象的建立过程,它把复杂对象的建立过程加以抽象,经过子类继承或者重载的方式,动态的建立具备复合属性的对象。
虽然与工厂模式、抽象工厂模式、单件模式同为建立型模式,但建造者模式与以前学习的模式相比,更为关注建立过程的细节,它通常用于建立复杂对象,从独立建立每一个部分到最后的组装,它承担每一个步骤的工做。因为它把建立每一个部分都独立为一个单一的过程,所以不只能够完成较为精细的建立,还能够根据建立步骤编排,生成不一样的目标实例。
GOF对建造者模式的描述是:
Separate the construction of a complex object from its representation so that the same construction process can create different representations..
— Design Patterns : Elements of Reusable Object-Oriented Software设计模式
建立者模式很是适用于产品局部加工过程变化较大,但组装过程相对固定的场景。
好比电脑的组装,基本的组装过程是固定的,可是具体主板、CPU、显卡、内存、硬盘等选择的品牌和型号可能差别很大;还有汽车的生产也是这样,总体组装过程基本相同,但不一样品牌、价格的汽车在具体部件上差别很大。markdown
其UML类图以下:
学习
其中包括三个角色:优化
这里的产品类型并无统一的IProduct接口,主要是由于通过不一样ConcreteBuilder加工后的产品差异相对较大,给它一个公共的基准抽象对象意义不大,ui
代码实现:设计
public class House { public void AddWindowAndDoor() { } public void AddWallAndFloor() { } public void AddCeiling() { } } public class Car { public void AddWheel() { } public void AddEngine() { } public void AddBody() { } } public interface IBuilder { void BuildPart1(); void BuildPart2(); void BuildPart3(); } public class CarBuilder : IBuilder { private Car car; public void BuildPart1() { car.AddEngine(); } public void BuildPart2() { car.AddWheel(); } public void BuildPart3() { car.AddBody(); } } public class HouseBuilder : IBuilder { private House house; public void BuildPart1() { house.AddWallAndFloor(); } public void BuildPart2() { house.AddCeiling(); } public void BuildPart3() { house.AddWindowAndDoor(); } } public class Director { public void Construct(IBuilder builder) { builder.BuildPart1(); builder.BuildPart2(); builder.BuildPart3(); } }
调用:3d
[Test] public void BuilderTest() { Director director = new Director(); CarBuilder carBuilder = new CarBuilder(); HouseBuilder houseBuilder = new HouseBuilder(); director.Construct(carBuilder); director.Construct(houseBuilder); Assert.AreEqual(typeof(Car), carBuilder.Car.GetType()); Assert.AreEqual(typeof(House), houseBuilder.House.GetType()); }
并且经典建造者中IBuilder定义了数目固定的装配动做,而Director有把这些动做的执行顺序也固定了,虽然建造者模式能够生产差别很是大的产品,但要求这些产品具备固定的装配步骤,这就大大局限了这种模式的使用场景,由于现实中这样的要求每每很难知足。不一样的产品每每具备数目不一样的装配动做和次序,若是要把这样的产品添加到建造者的生产列表中是作不到的,须要另外实现一套,改动比较大。code
上述问题能够经过对经典模式适当优化来解决。
IBuilder中定义的不一样步骤能够进一步抽象为一个Action,CarBuilder和HouseBuilder的代码也很类似,能够提取一个基类,这部分代码放在基类中。
代码以下:对象
public interface IBuilder<T> where T : class, new() { T BuildUp(); } public abstract class BuilderBase<T> : IBuilder<T> where T : class, new() { protected IList<Action> steps = new List<Action>(); protected T product = new T(); public virtual T BuildUp() { foreach (Action step in steps) { step(); } return product; } } public class ConcreteCarBuilder : BuilderBase<Car> { public ConcreteCarBuilder() : base() { steps.Add(product.AddEngine); steps.Add(product.AddWheel); steps.Add(product.AddBody); } } public class ConcreteHouseBuilder : BuilderBase<House> { public ConcreteHouseBuilder() : base() { steps.Add(product.AddWallAndFloor); steps.Add(product.AddCeiling); steps.Add(product.AddWindowAndDoor); } }
实体Builder兼作Director,具体的构建步骤由实体Builder来决定,这样作的好处是很是灵活,不一样的Builder能够有不一样数目的动做,动做的顺序也能够自行安排。blog
调用:
[Test] public void DelegateBuilderTest() { IBuilder<Car> builder = new ConcreteCarBuilder(); var product = builder.BuildUp(); Assert.AreEqual(typeof(Car), product.GetType()); IBuilder<House> builder1 = new ConcreteHouseBuilder(); var product1 = builder1.BuildUp(); Assert.AreEqual(typeof(House), product1.GetType()); }
参考书籍: 王翔著 《设计模式——基于C#的工程化实现及扩展》