建造者模式,有何妙用?

114 阅读3分钟

从建造者模式的定义上来看,使用多个简单的对象一步一步构建成一个复杂的对象。主要是在构建一个复杂对象时,将构建和表示分离。具体在什么场景使用,以及如何进行分离,比概念理解更加重要。

建造者模式,主要解决在创建一个复杂对象时,子对象不变,而组成方式不断变化的场景。

举个例子,假设我们有一个汽车类,该类具有多个复杂的属性,例如引擎、底盘、轮胎等。需要创建不同类型的汽车,跑车、轿车和SUV。构建汽车、轿车、SUV会有多种组合。借助建造者模式,我们可以实现这部分组合解耦。首先看下建造者模式的UML图是什么样的?

截屏2023-08-14 14.43.54.png

UML图中,可以看出,Build可以实现横向扩展,即需要增加子对象组合时,只需要扩展Build即可。

下面,就从代码上实现一个建造者模式

 // 管理者
    var Director = function (builder) {
        this.builder = builder;
    };

    Director.prototype.constructor = function (engine, chassis, tyres) {
        this.builder.buildEngine(engine);
        this.builder.buildChassis(chassis);
        this.builder.buildTyres(tyres);
        this.builder.build()
    }

    // 抽象构建者
    var AbstractBuilder = function () {};

    AbstractBuilder.prototype.setEngine = function (engine) {
        throw new Error("子类必须实现此方法");
    };

    AbstractBuilder.prototype.setChassis = function (chassis) {
        throw new Error("子类必须实现此方法");
    };

    AbstractBuilder.prototype.setTyres = function (tyres) {
        throw new Error("子类必须实现此方法");
    };

    // 实际构建者
    var Builder = function () {
        this.car = new Car()
    };
    Builder.prototype = Object.create(AbstractBuilder.prototype);
    Builder.prototype.constructor = Builder;

    Builder.prototype.buildEngine = function (engine) {
        this.car.engine = engine
    };

    Builder.prototype.buildChassis = function (chassis) {
        this.car.chassis = chassis
    };

    Builder.prototype.buildTyres = function (tyres) {
        this.car.tyres = tyres
    };


    Builder.prototype.build = function(){
        console.log("构建汽车")
        console.log("引擎",this.car.engine)
        console.log("底盘",this.car.chassis)
        console.log("轮胎",this.car.tyres)

        return this.car;
    }

    var Car = function () {}

    Car.prototype.engine = function (engine) {
        this.engine = engine
    }

    Car.prototype.chassis = function (chassis) {
        this.chassis = chassis
    }

    Car.prototype.tyres = function (tyres) {
        this.tyres = tyres
    }

    let builder = new Builder;
    let director = new Director(builder)

    let suv = director.constructor("v8_engine", "chassis_","tyres_")
    // 构建汽车
    // index.html:101 引擎 v8_engine
    // index.html:102 底盘 chassis_
    // index.html:103 轮胎 tyres_

这里可以采用一种链式调用的方式,使得组合更加的灵活。

 // 实际构建者
    var Builder = function () {
        this.car = new Car()
    };
    Builder.prototype = Object.create(AbstractBuilder.prototype);
    Builder.prototype.constructor = Builder;

    Builder.prototype.buildEngine = function (engine) {
        this.car.engine = engine
        return this
    };

    Builder.prototype.buildChassis = function (chassis) {
        this.car.chassis = chassis
        return this
    };

    Builder.prototype.buildTyres = function (tyres) {
        this.car.tyres = tyres
        return this
    };
  Director.prototype.constructor = function (engine, chassis, tyres) {
        this.builder.buildEngine(engine).buildChassis(chassis).buildTyres(tyres).build()
    }

这不是和工厂模式差不多嘛?那他们有什么区别?

  1. 创建方式:

    • 工厂模式:通过创建一个单独的类(工厂类)来负责创建其他类的实例,这个工厂类通常使用一个简单的方法来返回一个适当类型的对象。
    • 建造者模式:通过创建一个包含多个步骤或部件的复杂对象,并将这些步骤封装在一个单独的类(建造者类)中。建造者类通过调用其他对象的各种方法来逐步构建最终的对象。
  2. 关注点:

    • 工厂模式:关注于产品的创建,通常只关心最终创建的对象类型,而不关心对象的组成部分或创建过程。
    • 建造者模式:关注于产品的组成部分和创建过程,更注重细节和灵活性。建造者模式允许你在构建过程中逐步添加或删除部件,而无需改变其他部分的代码。
  3. 灵活性:

    • 工厂模式:在需要创建多种类型对象的情况下,工厂模式可以提供一种简单且一致的方式来创建对象。但是,如果对象的创建过程需要大量自定义或复杂的步骤,工厂模式可能会变得过于复杂。
    • 建造者模式:提供更大的灵活性,可以方便地修改和扩展对象的创建过程,以满足特定的需求。然而,由于建造者模式需要显式地调用每个步骤,因此在创建简单对象时可能会显得过于复杂。

因此,在创建对象的时候,有很多参数需要配置,组合场景还多的时候,可以采用建造者模式,便于扩展。