设计模式之生成器模式

SegmentFault

共 3086字,需浏览 7分钟

 ·

2020-11-29 01:08

作者:Aaron

来源:SegmentFault 思否社区




生成器模式又叫做建造者模式,之前介绍的一些创建型的设计模式基本都比较简单的,生成器模式是较为复杂的创建型模式,它将客户端与包含多个组成部分的复杂对象的创建过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。


它关注如何一步一步创建一个的复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无须修改已有代码,系统具有较好的拓展性。




什么是生成器模式


生成器模式:是一种设计模式,又名:建造模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。—— 节选自维基百科


例如,我们来思考如何创建一辆汽车对象。创造一辆简单的汽车,首先需要创建车的框架和车轱辘,然后安装汽车门、汽车玻璃,最后再安装上发动机。但是如果你想要一个性能更好的汽车的话,那么还需要给汽车加上一些其他的设施,这个时候咱们需要怎么去做呢?


最简单的方法是拓展原有汽车的基类,然后创建一系列涵盖所有参数组合的子类。但最终将面对相当数量的子类。任何新增的参数都会让这个层次结构更加复杂。


另一种方法则无需生成子类。可以再汽车的基类中创建一个包括所有可能参数的超级构造函数,并用它来控制汽车对象。这种方法可以避免生成子类,但它却会造成另外一个问题。通常情况下,绝大部分的参数都没有使用,这使得对于构造函数的调用十分不简洁。




生成器模式优缺点


生成器模式会将对象构造过程划分为一组步骤,每次创建对象时,你都需要通过生成器对象执行一系列步骤。重点在于你无需调用所有步骤,而只需调用创建特定对象配置所需的那些步骤即可。当你需要创建不同形式的产品时,其中的一些构造步骤可能需要不同的实现。可以创建多个不同的生成器, 用不同方式实现一组相同的创建步骤。然后你就可以在创建过程中使用这些生成器 (例如按顺序调用多个构造步骤) 来生成不同类型的对象。


优点


  1. 在生成器模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
  2. 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合开闭原则
  3. 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

缺点

  1. 生成器模式所生成的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制
  2. 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本



示例

生成器模式的主要角色如下:

  1. 生成器:接口生命再所有类型生成器中通用的产品构造步骤
  2. 具体生成器:提供构造过程的不同实现。具体生成器也可以构造不遵循通用接口的产品
  3. 产品:是最终生成的对象。由不同生成器构造的产品无需属于同一类层次构造或接口
  4. 指挥者:定义调用构造步骤的顺序,这样你就可以创建和服用特定的产品配置
  5. 客户端:必须将某个生成器对象与主管类关联,一般情况下,你只需要通过指挥者类构造函数的参数进行一次性关联即可

类图如下所示:


代码示例:

// 抽象建造者
abstract class Builder {
    public abstract buildPartA():void;
    public abstract buildPartB():void;
    public abstract buildPartC():void;
    public abstract buildProduct():Product;
}

// 具体建造者
class ConcreteBuilder extends Builder {
    private product:Product;
    constructor(product:Product) {
        super();
        this.product = product;
    }

    public buildPartA():void {}
    public buildPartB():void {}
    public buildPartC():void {}

    // 最终组建一个产品
    public buildProduct():Product {
        return this.product;
    }
}

// 产品角色
class Product {
    public doSomething():void {
        // 独立业务
    }
}

// 指挥者
class Director {
    private _builder:Builder;
    constructor(builder:Builder) {
        this._builder = builder;
    }

    set builder(builder:Builder) {
        this._builder = builder;
    }

    // 将处理建造的流程交给指挥者
    public constructorProduct() {
        this._builder.buildPartA();
        this._builder.buildPartB();
        this._builder.buildPartC();
        return this._builder.buildProduct();
    }
}

// 使用
const builder:Builder = new ConcreteBuilder(new Product());
const director:Director = new Director(builder);
const product:Product = director.constructorProduct();



总结

生成器模式的主要功能是构建复杂的产品,而且是细化的,分步骤的构建产品,也就是生成器模式重在一步一步解决构造复杂对象的问题。如果仅仅这么认知生成器模式的功能是不够的。更为重要的是,这个构建的过程是统一的、固定不变的,变化的部分放到生成器部分了,只要配置不同的生成器,那么同样的构建过程,就能构建出不同的产品来。

虽然在生成器模式的整体构建算法中,会一步一步引导Builder来构建对象,但这并不是说生成器主要就是用来实现分步骤构建对象的。生成器模式的重心还是在于分离整体构建算法和部件构造,而分步骤构建对象不过是整体构建算法的一个简单表现,或者说是一个附带产物。



点击左下角阅读原文,到 SegmentFault 思否社区 和文章作者展开更多互动和交流。

- END -

浏览 47
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报