设计模式(4) 建造者模式

  • 什么是建造者模式
  • 经典建造者模式的优缺点
  • 对建造者模式的扩展

什么是建造者模式

建造者模式将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。创建者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。
虽然与工厂模式、抽象工厂模式、单件模式同为创建型模式,但建造者模式与之前学习的模式相比,更为关注创建过程的细节,它一般用于创建复杂对象,从独立创建每个部分到最后的组装,它承担每个步骤的工作。由于它把创建每个部分都独立为一个单一的过程,因此不仅可以完成较为精细的创建,还可以根据创建步骤编排,生成不同的目标实例。
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、显卡、内存、硬盘等选择的品牌和型号可能差异很大;还有汽车的生产也是这样,整体组装过程基本相同,但不同品牌、价格的汽车在具体部件上差异很大。

其UML类图如下:

其中包括三个角色:

  • IBuilder:负责描述创建一个产品各个组成的抽象接口。
  • Concrete Builder:实现IBuilder要求的内容,并且提供一个获得产品的方法。
  • Director:基于IBuilder定义的构造产品的抽象步骤,指导Concrete Builder生成产品的过程。

这里的产品类型并没有统一的IProduct接口,主要是因为经过不同ConcreteBuilder加工后的产品差别相对较大,给它一个公共的基准抽象对象意义不大,

代码实现:

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();
    }
}

调用:

[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());
}

经典建造者模式的优缺点

  • 优点:创建者模式将复杂对象的每个组成创建步骤暴露出来,借助Director(或客户程序自己)既可以选择其执行次序,也可以选择要执行哪些步骤。上述过程可以在应用中动态完成,相比较工厂方法和抽象工厂模式的一次性创建过程而言,创建者模式适合创建“更为复杂且每个组成变化较多”的类型。
  • 缺点:但建造者模式也存在一些缺点,比如正因为会暴露出更多的执行步骤,这就需要需要Director(或客户程序)具有更多的领域知识,使用不慎很容易造成相对更为紧密的耦合。

而且经典建造者中IBuilder定义了数目固定的装配动作,而Director有把这些动作的执行顺序也固定了,虽然建造者模式可以生产差异非常大的产品,但要求这些产品具有固定的装配步骤,这就大大局限了这种模式的使用场景,因为现实中这样的要求往往很难满足。不同的产品往往具有数目不同的装配动作和次序,如果要把这样的产品添加到建造者的生产列表中是做不到的,需要另外实现一套,改动比较大。

对建造者模式的扩展

上述问题可以通过对经典模式适当优化来解决。
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可以有不同数目的动作,动作的顺序也可以自行安排。

调用:

[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#的工程化实现及扩展》

(0)

相关推荐

  • ​PHP设计模式之建造者模式

    PHP设计模式之建造者模式 建造者模式,也可以叫做生成器模式,builder这个词的原意就包含了建筑者.开发者.创建者的含义.很明显,这个模式又是一个创建型的模式,用来创建对象.那么它的特点是什么呢? ...

  • 创建型模式————建造者模式(2.4)

    什么是建造者模式? 工厂模式聚焦于创建出一个对象,而建造者除此之外还需要为创建的对象赋值. 简单来说,建造者模式=创建对象+属性赋值. 建造者模式应用场景 建造者模式适合创建类中包含多个参数且需要定制 ...

  • 设计模式之建造者模式

    设计模式之建造者模式

  • 建造者模式(Bulider模式)详解

    在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成.例如,计算机是由 CPU.主板.内存.硬盘.显卡.机箱.显示器.键盘.鼠标等部件组装而成的,采购员不可能自 ...

  • 设计模式-创建型-建造者模式

    引言: 无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如汽车,它包括车轮.底盘.发动机.方向盘等各种部件.而对于大部分用户而言,无须知道这些部件的装配细节,也几乎不会 ...

  • [PHP小课堂]PHP设计模式之建造者模式

    [PHP小课堂]PHP设计模式之建造者模式 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[DarkMatterZyCoder/149844827]免费得PHP.项目管理学习资料

  • 设计模式系列 | 建造者模式

    想自己的开发路子走得更远更久,想成为更牛的码农,那设计模式的理解和掌握是必须的. 老田,能详细说说你的段位2吗? 很多人也都听说过建造者设计模式,但总是对这个设计模式理解得不够透彻,今天我们就来聊聊建 ...

  • 设计模式-建造者模式

    建造者模式 也叫生成器模式,他是一个创建型模式 通用类图 Product产品类 ​通常是实现了模板方法模式,也就是有模板方法和基本方法. public class Product { public v ...

  • 设计模式模式(四):建造者模式(生成器模式)

    建造者模式主要解决问题: 具备若干成员,当其中一个成员发生变化,其它成员也随着发生变化. 这种复杂对象的生成需要使用建造者模式来生成. 建造者设计模式的结构图: 来源:http://c.bianche ...

  • 设计模式 | 建造者模式/生成器模式(builder)

    定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 结构:(书中图,侵删) 一个产品类 一个指定产品各个部件的抽象创建接口 若干个实现了各个部件的具体实现的创建类 一个 ...

  • 通俗易懂系列 | 设计模式(八):建造者模式

    介绍# 今天我们将研究java中的Builder模式.Builder 设计模式是一种创造性的设计模式,如工厂模式和抽象工厂模式. 当Object包含许多属性时,引入了Builder模式来解决Facto ...