JavaScript 设计模式 : 巧用'工厂模式'和'建立者'模式

我为何把他们两个放在一块儿讲?我以为这两个设计模式有类似之处,有时候会一个设计模式不能知足你的需求而采用另外一种设计模式。基于这点考虑,并且为了你们更好地理解,我放到了一块儿,加深你们的印象,活学活用。编程

[这里我为了能更好的体现下设计模式与JS本体语言的结合,我用了一点继承关系.
有的同窗都不知道JS能继承,就算你们不懂继承也但愿你们能看下去,弄懂它!]
复制代码

本文扩展

掘金有个文章继承仍是蛮透彻的 JS原型链与继承别再被问倒了后端

工厂模式

  • 建立对象跟对不一样需求进行不一样的实例化

在咱们Team协做开发过程中,不一样于咱们写我的项目,对全局变量的限制很大,咱们要尽可能少的使用全局变量,对于一类对象在不一样需求上的不一样使用,甚至将一些有些相似的方法抽象化,能够用工厂模式来负责建立这些对象,调用者可使用一部分资源也能够在基础上私人订制一套资源。设计模式

就拿昨天入群的小伙伴举个栗子:他设计一个网页播放器有四个按钮:bash

咱们不讨论他的实现方式,咱们按照工厂模式来简单建立一个吧!框架

function wangyiMusicAction(action){
    var o = new Object;
    o.vender = '网易云音乐';
    o.playingMusic = 'see you again'
    switch (action){
        case 'last':
            o.information = {currentMusic:'Ich will',status:'200|404',message:'上一曲'}
            break
        case 'next':
            o.information = {currentMusic:'一人我编程累',status:'200|404',message:'下一曲'}
            break
        case 'play':
            o.information = {currentMusic:'see you again',status:'200|500',message:'播放'}
            break
        case 'mute':
            o.information = {currentMusic:'see you again',status:'200|500',message:'静音'}
            break
    }
    return o;

}
var music = wangyiMusicAction('next')
console.log('音乐提供商 : '+music.vender);
console.log('正在播放 : '+music.playingMusic);
console.log('执行动做 : ' +music.information.message);
console.log('接口状态 : ' +music.information.status);
console.log('执行动做后歌曲 : ' +music.information.currentMusic);

----------执行结果--------

音乐提供商 : 网易云音乐
正在播放 : see you again
执行动做 : 下一曲
接口状态 : 200|404
执行动做后歌曲 : 一人我编程累
复制代码

这其实使咱们常用的,不过这是面向过程的,不太符合咱们的设计模式。咱们用上篇学到的模式:对象函数

咱们能够修改一下:ui

var WangyiMusicAction = function(action){

    this.vender = '网易云音乐';
    this.playingMusic = 'see you again'

}

WangyiMusicAction.prototype = {
    last : function() {
            this.information = {currentMusic:'Ich will',status:'200|404',message:'上一曲'}
        },

    next : function() {
            this.information = {currentMusic:'一人我编程累',status:'200|404',message:'下一曲'}
        },

    play : function() {
            this.information = {currentMusic:'see you again',status:'200|500',message:'播放'}
        },

    mute : function() {
            this.information = {currentMusic:'see you again',status:'200|500',message:'静音'}
        }

}

var music = new WangyiMusicAction()
music.next(); //执行下一曲动做
console.log('音乐提供商 : '+music.vender);
console.log('正在播放 : '+music.playingMusic);
console.log('执行动做 : ' +music.information.message);
console.log('接口状态 : ' +music.information.status);
console.log('执行动做后歌曲 : ' +music.information.currentMusic);
音乐提供商 : 网易云音乐
正在播放 : see you again
执行动做 : 下一曲
接口状态 : 200|400

----------执行结果--------

执行动做后歌曲 : 一人我编程累

复制代码

这样就算是面向对象的了,虽然达到目的,可是上面所说的,可是这算是Music的网易云音乐实现版本、总不能再来一个QQMusicXiaMiMusic吧?咱们创建一个Factory工厂来管理全部的音乐:this

var WangyiMusicAction = function(action){

    this.vender = '网易云音乐';
    this.playingMusic = 'see you again'

}

//为网易音乐提供共有方法
WangyiMusicAction.prototype = {
    last : function() {
        this.information = {currentMusic:'Ich will',status:'200|404',message:'上一曲'}
    },

    next : function() {
        this.information = {currentMusic:'一人我编程累',status:'200|404',message:'下一曲'}
    },

    play : function() {
        this.information = {currentMusic:'see you again',status:'200|500',message:'播放'}
    },

    mute : function() {
        this.information = {currentMusic:'see you again',status:'200|500',message:'静音'}
    }

}


var QQMusicAction = function(action){

    this.vender = 'QQ音乐';
    this.playingMusic = '其实我不low'

}

//为QQ音乐提供共有方法
QQMusicAction.prototype = {
    last : function() {
        this.information = {currentMusic:'Ich will',status:'200|404',message:'上一曲'}
    },

    next : function() {
        this.information = {currentMusic:'网易才low',status:'200|404',message:'下一曲'}
    },

    play : function() {
        this.information = {currentMusic:'see you again',status:'200|500',message:'播放'}
    },

    mute : function() {
        this.information = {currentMusic:'see you again',status:'200|500',message:'静音'}
    }

}
//音乐工厂
var MusicFactory = function(type){
    switch (type){
        case 'qq':
            return new QQMusicAction();

        case 'wangyi':
            return new WangyiMusicAction()
    }
}


var music = new MusicFactory('qq')
music.next(); //执行下一曲动做
console.log('音乐提供商 : '+music.vender);
console.log('正在播放 : '+music.playingMusic);
console.log('执行动做 : ' +music.information.message);
console.log('接口状态 : ' +music.information.status);
console.log('执行动做后歌曲 : ' +music.information.currentMusic);

----------执行结果--------

音乐提供商 : QQ音乐
正在播放 : 其实我不low
执行动做 : 下一曲
接口状态 : 200|404
执行动做后歌曲 : 网易才low

复制代码

这样调用者须要用音乐接口,只须要记住MusicFactory就能够了,MusicFactory就像一个大工厂,对于music能够返回他要的一切。spa

好,咱们回过头来看一下:prototype

第一种方法:是建立一个新的对象 o 对他来加强 属性 的功能来实现的. 第二种方法:是实例化对象来建立的。 第二种方法:若是他们继承同一个父类 BaseMusic 那么他们父类的原型方法是能够和它们公用的! 第一种方法:咱们内部 new 了一个新的个体,就不能与父类共用了.

具体哪一种仍是看你需求的,不过我更倾向第二种,由于他扩展性高,需求多的时候咱们甚至能够将通用的抽离出来放到父类BaseMusic中。

在下面的继承中我运用了类式继承

ps:(你们能够看看构造函数继承和组合继承连接在最下面)
复制代码
//基类(父类)music方法
var BaseMusic = function(){
    this.playingMusic = 'see you again'
}
//实现通用方法
BaseMusic.prototype = {
    last : function() {
        this.information = {status:'200|404',message:'上一曲'}
    },

    next : function() {
        this.information = {currentMusic:'一人我编程累',status:'200|404',message:'下一曲'}
    },

    play : function() {
        this.information = {currentMusic:'see you again',status:'200|500',message:'播放'}
    },

    mute : function() {
        this.information = {currentMusic:'see you again',status:'200|500',message:'静音'}
    }
}
//网易云的不一样于父类的构造方法
var WangyiMusicAction = function(action){

    this.vender = '网易云音乐';

}
//这里经过prototype实现类继承
WangyiMusicAction.prototype = new BaseMusic();//这些动做我都放在基类了,达到代码复用的目的
 
//QQ
var QQMusicAction = function(action){

    this.vender = 'QQ音乐';
    this.playingMusic = '其实我不low'

}
QQMusicAction.prototype = new BaseMusic() //这些动做我都放在基类了,达到代码复用的目的

//音乐工厂
var MusicFactory = function(type){
    switch (type){
        case 'qq':
            return new QQMusicAction();

        case 'wangyi':
            return new WangyiMusicAction()
    }
}


var music = new MusicFactory('wangyi')
music.next(); //执行下一曲动做
console.log('音乐提供商 : '+music.vender);
console.log('正在播放 : '+music.playingMusic);
console.log('执行动做 : ' +music.information.message);
console.log('接口状态 : ' +music.information.status);
console.log('执行动做后歌曲 : ' +music.information.currentMusic);

----------执行结果--------

音乐提供商 : 网易云音乐
正在播放 : see you again
执行动做 : 下一曲
接口状态 : 200|404
执行动做后歌曲 : 一人我编程累
复制代码

这样看起来是否是更好、更简洁呢?

建立者模式

  • 工厂模式职责:我无论你想干啥,我只返回给你一个你想要的对象
  • 建立者模式职责:主要针对复杂业务的解耦,算是工厂的一种拆解、拼接。我能够将你的需求分解多个对象建立,更关心的是建立对象的过程。

不复杂不能突显出他的魅力,举个稍微复杂栗子:

咱们公司是卖车的,用户下单要买车,这个车呢:

品牌:迈巴赫、林肯、宾利、特斯拉[若是不选品牌,默认特斯拉] 
颜色:赤橙黄绿青蓝紫...[若是不选颜色,默认黄色]
动力:燃油、电力、混合动力[若是不选动力,默认电力]
购买人的一些备注信息[购买人可能会修改备注须要提供方法]
针对购买人选择的车型返回对车型的简单描述[描述能够修改]

复制代码

最终根据用户选择来生成一个订单: 想下这用工厂模式是否是要写不少的if else来返回这么一个Car的对象呢?

咱们先将 购买人的动做 反馈 分解为三个对象再在最后进行拼接 :

//建立一个汽车
var Car  = function(param){
    this.color = param && param.color || 'yellow';
    this.brand = param && param.brand || 'Tesla';
    this.power = param && param.power || 'electric';
}
//提供原型方法
Car.prototype = {
    getColor : function () {
        return this.color;
    },
    getBrand : function () {
        return this.brand;
    },
    getPower : function () {
        return this.power;
    }
}

//建立一个反馈
var FeedBack = function(brand){
    var that = this;
    (function(brand,that){
        switch (brand){
            case 'Tesla':
                // that.brand = brand;
                that.information = '特斯拉是好车'
                break
            case 'Rolls' :
                that.information = '劳斯来时是好车'
        }
    })(brand,that)
}

FeedBack.prototype.changeBrand = function (information) {
    this.information = information;
}


//建立一个顾客
var Client = function(name,message){
    this.name = name;
    this.message = message || '无留言';
}
//顾客修改备注
Client.prototype.changeMessage = function(message){
    this.message = message;
}
//而后重点在这里!咱们在这里将咱们分解的拼接起来。
var Order = function(name){
    var object = new Car();
    object.client  = new Client(name);
    object.feedBack = new FeedBack(object.brand);
    return object;
}


var orderCar = new Order('Vendar-MH');
console.log('The' + orderCar.client.name + '先生、下单一辆' + orderCar.color + '的' + orderCar.brand +' 留言内容 : ' +orderCar.client.message );
orderCar.client.changeMessage('请立刻电话联系我')
console.log('The' + orderCar.client.name + '先生、下单一辆' + orderCar.color + '的' + orderCar.brand +' 留言内容 : ' +orderCar.client.message );

----------执行结果--------

TheVendar-MH先生、下单一辆yellow的Tesla 留言内容 : 无留言
TheVendar-MH先生、下单一辆yellow的Tesla 留言内容 : 请立刻电话联系我

复制代码

好了,就算是关于这个订单的更加复杂的需求,或者修改需求,无论咱们多少各功能在用,咱们只要微微一笑,修改下prototype等实现就行了0.0

若是您以为还算不错能够关注我持续看个人文章,大概方向:先后端语言设计模式如何设计好一款框架源码导读技术实践

  • 青年才俊能够入群交流:147255248
相关文章
相关标签/搜索