JavaScript设计模式系列二之建造者模式(附案例源码)

文章初衷

设计模式其实旨在解决语言本身存在的缺陷,

目前javaScript一些新的语法特性已经集成了一些设计模式的实现,

大家在写代码的时候,没必要为了用设计模式而去用设计模式,

那么我这边为什么还写设计模式的文章呢,

一方面是自己的一个整理,然后记录出来,结合自己的理解,

一方面就是虽然语言特性本身已经实现这些模式,有了自己的语法,

但是我们何尝不能去了解一下它是通过什么样的思路去实现了

在我看来设计模式更多的是让我对于思考问题,有了一些更好的思路和想法

文章实现更多的表现为用一些简单的案例,帮助大家去理解这样的一种思路,

会存在故意把设计模式的实现往简单的案例靠拢,

大家在真实项目中不要刻意去用设计模式实现相同的代码

设计模式在平时的一些代码中都会有所体现,大家也许经常用到,

耐心看文章,也许你会发现自己平时的代码就不断在设计模式中体现

JavaScript设计模式系列

JavaScript设计模式系列,讲述大概20-30种设计模式在JavaScript中的运用

后面对应的篇幅会陆续更新,欢迎大家提出建议

这是设计模式系列第二篇,讲述建造者模式

上篇文章讲述了工厂设计模式,有兴趣可以查看

注意

JavaScript设计模式系列github地址

深入系列文章部分是有先后顺序的,按照目录结构顺序阅读效果最好。

勘误及提问

如果有疑问或者发现错误,可以在相应的 issues 进行提问或勘误。

如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。

建造者模式

概念:

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建

不同的表示。

不管扯淡的概念,上🌰,后面再反过头来理解这句话

// #建造者模式 


// 抽象建造者
var Car = function (param) {
    // 速度
    this.speed = param && param.speed || '0';
    // 重量
    this.weight = param && param.weight || '0';
}


Car.prototype = {
    // 获取速度
    getSpeed: function () {
        return this.speed;
    },
    // 获取重量
    getWeight: function () {
        return this.weight
    }
}

// 轮胎部件类
var Tyre = function (type) {
    var that = this;
    // 构造器
    // 构造函数中通过传入的type类型设置相对应的轮胎尺寸
    (function (type,that) {
        switch (type) {
            case 'small':
            that.tyre = '小号轮胎';
            that.tyreIntro = '正在使用小号轮胎';
            break;
            case 'normal':
            that.tyre = '中号轮胎';
            that.tyreIntro = '正在使用中号轮胎';
            break;
            case 'big':
            that.tyre = '大号轮胎';
            that.tyreIntro = '正在使用大号轮胎';
            break;
        }
    })(type,this);
}


Tyre.prototype = {
    // 更换轮胎的方法
    changeType: function (type) {
        that.tyre = type;
        that.tyreIntro = '正在使用'+type;
    }
}


// 发动机部件类
var Engine = function (type) {
    var that = this;
    // 构造器
    // 构造函数中通过传入的type类型设置相对应的发动机类型
    (function (type,that) {
        switch (type) {
            case 'small':
            that.engine = '小号发动机';
            that.engineIntro = '正在使用小号发动机';
            break;
            case 'normal':
            that.engine = '中号发动机';
            that.engineIntro = '正在使用中号发动机';
            break;
            case 'big':
            that.engine = '大号发动机';
            that.engineIntro = '正在使用大号发动机';
            break;
        }
    })(type,this);
}


Engine.prototype = {
    // 更换发动机的方法
    changeType: function (type) {
        that.engine = type;
        that.engineIntro = '正在使用'+type;
    }
}

/**
 * 指挥者,建造一个奔驰车的类
 * @param {*轮胎类型 small normal big} tyre 
 * @param {*发动机类型 small normal big} engine 
 * @param {*车辆基本属性 param.speed:速度 param.weight: 重量} param 
 */
var BenChi = function (tyre,engine,param) {
    // 创建一个车辆缓存对象
    var _car = new Car(param);
    // 创建车辆的轮胎
    _car.tyreInfo = new Tyre(tyre);
    // 创建车辆的发动机
    _car.engineInfo = new Engine(engine);
    // 将创建的车辆对象返回
    return _car;
}

// 具体建造者 实例化奔驰车类
var benchi1 = new BenChi('small','big',{speed: 200,weight: '200'});
console.log(benchi1.speed);// 200
console.log(benchi1.weight);// 200
console.log(benchi1.tyreInfo.tyre);// 小号轮胎
console.log(benchi1.tyreInfo.tyreIntro);// 正在使用小号轮胎
console.log(benchi1.engineInfo.engine);// 大号发动机
console.log(benchi1.engineInfo.engineIntro);// 正在使用大号发动机

// #建造者模式end复制代码

这段例子是这样的意思,首先我们要建造一个车,

那么车是一个比较复杂的东西,我们需要轮胎部件,发动机部件等等其他

复杂的部件,每个部件相对来说又是独立的个体,又是具备很多独立的行为

那么针对这种复杂的对象(例子中是一辆车),我们把它分成一个个部件,

然后通过一系类的组装,把这些部件都拼接在一起,组成一个复杂的对象,

这样的方式就是建造者模式,一步步构建一个复杂的对象,

用户只关心最后建造出来的车,不需要关心它具体的部件是如何实现的

建造者模式中存在的角色

这边介绍一下建造者模式中存在的角色,方便大家去理解

  • 抽象建造者
  • 指挥者
  • 具体建造者

结合上面的案例,我们去把案例中的情况根据角色去划分一下,

这样更好的去理解建造者模式

首先Car就是抽象建造者,它具备一些车的基本属性还有方法,

它是抽象的,用户不需要知道它的存在,

那么Tyre(轮胎),Engine(发动机),分别就是车的具体部件(具体类),

创建的BenChi类,其实就是一个指挥者的角色,负责把对应的部件组装起来,

具体创建一个什么样子的车,就是指挥者这边决定的,

比如说这边还有一个空调部件,有些车没有的话,那么指挥者在创建的时候,

就不需要加入这个部件,所以对象的建造都是指挥者这边决定的

再下面就是具体建造者了,指挥者创建了一个奔驰车的类,

那么具体建造者,通过调用这个类去实现不同的车系,

比如奔驰车它有很多系列,通过传递不同的参数,就可以创建不同的系列

这就是一个完整的建造者案例,把复杂对象简单化,通过建造不同的部件类,

组成一个复杂的对象,不同的部件,在创建不同对象的时候,可以进行复用。

建造者模式的优点

  • 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象

  • 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象

  • 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

  • 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”

建造者模式的缺点

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

建造者模式的适用情况

  • 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。

  • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建
    不同的产品。

工厂模式与建造者模式的比较

相关工厂模式的内容,可以查看工厂设计模式

  • 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,
    而抽象工厂模式返回一系列相关的产品
    ,这些产品位于不同的产品等级结构,构成了一个产品族。
  • 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,
    它侧重于一步步构造一个复杂对象,返回一个完整的对象
  • 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,
    那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。

建造者模式的总结

  • 建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。建造者模式属于对象创建型模式。

  • 建造者模式包含3个角色,抽象建造者创建对象的基本属性方法,
    指挥者用来组装具体的部件,形成不同的对象,具体建造者负责实现指挥者创建的对象

最后我们再来理解建造者模式的概念就比较简单了:

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建

不同的表示。

注意

JavaScript设计模式系列github地址

深入系列文章部分是有先后顺序的,按照目录结构顺序阅读效果最好。

关于设计模式,更多的是结合我自己的一些理解,把他总结出来分享给大家,如果大家发现有什么不正确的地方,希望大家一定得提出来,避免我这边误人子弟,感谢大家!!!

    原文作者:算法小白
    原文地址: https://juejin.im/post/59b5fb3cf265da064b46ca14
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞