JavaScript

16种JavaScript设计模式(下)

2020-04-08  本文已影响0人  嘿哟写bug呢

## 简介

紧接[上文(地址)](https://www.jianshu.com/p/993027963b60),我们继续介绍以下几种设计模式

* 模板方法模式

* 享元模式

* 责任链模式

* 中介者模式

* 装饰者模式

* 状态模式

* 适配器模式

#### 模板方法模式

定义:基于继承的设计模式,在父类中定义需要实现的方法,并定义好方法的执行逻辑,子类只需实现对应方法即可

简介:模板方法模式是一种只需通过继承就可以实现的简单模式。这种模式在前端框架中十分常见,vue、react的组件定义都用到了该模式。大家思考下为什么我们在vue组件中定义的生命周期函数会按照给定的顺序执行呢?通过下面的简单示例来了解下。

例:

```

var Vue = function (config) { // 父类

    this.config = config

}

// 定义需要实现的方法

Vue.prototype.created = function () {}

Vue.prototype.mounted = function () {}

Vue.prototype.destoryed = function () {}

// 定义执行逻辑

Vue.prototype.init = function () {

    this.created()

    this.mounted()

    this.destoryed()

}

var Button = function (config) {

    Vue.call(this, config)

}

Button.prototype = new Vue()

Button.prototype.created = function () {

    console.log('button created')

}

Button.prototype.mounted = function () {

    console.log('button mounted')

}

Button.prototype.destoryed = function () {

    console.log('button destoryed')

}

var button = new Button()

```

#### 享元模式

定义:将对象属性划分为内、外两种属性,共享内部状态节约内存

简介:享元模式是一种用于性能优化的模式,避免创建大量类似的对象,占用大量内存。

例:

```

var Hero = function (name) {

    this.name = name // 内部状态

}

Hero.prototype.show = function () {

    console.log('我', this.name, '的新皮肤-', this.skin, '可真好看')

}

var GayLun = new Hero('盖伦')

var skins = ['乞丐装', '官人装', '皇帝装']

for (var index = 0; index < skins.length; index++) {

    GayLun.skin = skins[index]; // 外部状态

    GayLun.show()

}

```

#### 责任链模式

定义:将一系列处理方法连成链条,请求在这个链条中传递,直到遇到一个可以处理它的方法。

简介:如果大家接触过node开发,可能会比较好理解这个模式。node开发中我们会定义许多中间件依次挂载到node实例上。当服务器收到请求时请求回依次通过这些中间件方法,这些方法收到请求对象时会判断并处理该请求,然后传给下一个方法。

```

var ming = function(next, subject){

    console.log(next);

    if ( subject === '1+1' ){

        console.log( '这题我会是2' )

    } else {

        next(subject) //我不知道下一个节点是谁,反正把请求往后面传递

    }

};

var zhang = function(next, subject){

    if ( subject === '1-1' ){

        console.log( '这题我会是0' )

    } else {

        next(subject) //我不知道下一个节点是谁,反正把请求往后面传递

    }

};

var wang = function(next, subject){

    if ( subject === '1*1' ){

        console.log( '这题我会是1' )

    } else {

        next(subject) //我不知道下一个节点是谁,反正把请求往后面传递

    }

};

var Chain = function() {

    this.line = []

    this.index = 0

}

Chain.prototype.add = function(fn) {

    this.line.push(fn)

}

Chain.prototype.exec = function() {

    this.line[this.index](this.next.bind(this), ...arguments)

}

Chain.prototype.next = function() {

    var fn = this.line[++ this.index]

    if(fn) {

        fn.apply(this, [this.next.bind(this), ...arguments])

    } else {

        console.log('end')

    }

}

var studentChain = new Chain()

studentChain.add(ming)

studentChain.add(zhang)

studentChain.add(wang)

studentChain.exec('1+1')

```

#### 中介者模式

定义:解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的 相关对象都通过中介者对象来通信。

简介:中介者使各对象之间耦合松散,而且可以独立地改变它们之间的交互。中介者

模式使网状的多对多关系变成了相对简单的一对多关系。中介者也被称为调停者,我们想象一下机场的指挥塔,如果没有指挥塔的存在,每一架飞机 要和方圆 100 公里内的所有飞机通信,才能确定航线以及飞行状况,后果是不可想象的。现实中 的情况是,每架飞机都只需要和指挥塔通信。指挥塔作为调停者,知道每一架飞机的飞行状况, 所以它可以安排所有飞机的起降时间,及时做出航线调整。

```

function Airplane(num) {

    this.num = num

    this.state = 'out'

}

function Airport(maxCount) {

    this.planes = []

    this.maxCount = maxCount

}

Airport.prototype.enter = function (plane) {

    var count = this.planes.filter(e => e.state !== 'out').length

    if(count < this.maxCount) {

        var exist = this.planes.find(e => e.num === plane.num)

        if(exist) {

            exist.state = 'in'

        } else {

            plane.state = 'in'

            this.planes.push(plane)

        }

        console.log('运行降落');

    } else {

        console.log('满了你飞别处去吧');

    }

}

Airport.prototype.leave = function (plane) {

    var exist = this.planes.find(e => e.num === plane.num)

    exist.state = 'out'

}

var plane1 = new Airplane('1-1')

var plane2 = new Airplane('1-2')

var plane3 = new Airplane('1-3')

var airport = new Airport(2)

airport.enter(plane1)

airport.enter(plane2)

airport.enter(plane3)

airport.leave(plane2)

airport.enter(plane3)

```

#### 装饰者模式

定义:给对象动态地增加职责的方式称为装 饰者(decorator)模式

简介:装饰者模式能够在不改 变对象自身的基础上,在程序运行期间给对象 动态地添加职责。跟继承相比,装饰者是一种 更轻便灵活的做法(超类和子类之间存在强耦合性,当超类改变时,子类也会随之 改变)

例:在飞机大战游戏中,我们可以吃到一些额外的的武器包来强化我们的小飞机

```

var Plane = function () {

    this.plane = plane;

}

Plane.prototype.fire = function () {

    console.log('发射子弹');

}

var MissileDecorator = function (plane) {

    this.plane = plane;

}

MissileDecorator.prototype.fire = function () {

    this.plane.fire();

    console.log('两侧发射导弹');

}

var plane = new Plane();

plane = new MissileDecorator(plane);

plane.fire();

```

#### 状态模式

定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

简介:状态模式的关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变。

相对于策略模式来说状态模式中,状态 和状态对应的行为是早已被封装好的,状态之间的切换也早被规定完成,“改变行为”这件事情 发生在状态模式内部。对客户来说,并不需要了解这些细节。这正是状态模式的作用所在。

例:电灯开关

```

var OffLightState = function (light) {

    this.light = light;

};

OffLightState.prototype.buttonWasPressed = function () {

    console.log('开灯'); // offLightState 对应的行为

    this.light.setState(this.light.onLightState); // 切换状态到onLightState

};

// WeakLightState:

var OnLightState = function (light) {

    this.light = light;

};

OnLightState.prototype.buttonWasPressed = function () {

    console.log('关灯'); // onLightState 对应的行为

    this.light.setState(this.light.offLightState); // 切换状态到offLightState

};

var Light = function () {

    this.offLightState = new OffLightState(this);

    this.onLightState = new OnLightState(this);

    this.currState = this.offLightState;

};

Light.prototype.buttonWasPressed = function () {

    this.currState.buttonWasPressed();

};

Light.prototype.setState = function (newState) {

    this.currState = newState;

};

var light = new Light();

light.buttonWasPressed() // 开灯

light.buttonWasPressed() // 关灯

```

#### 适配器模式

定义:通过包装函数,统一接口定义

简介:适配器模式主要用来解决两个已有接口之间不匹配的问题,它不考虑这些接口是怎样实 现的,也不考虑它们将来可能会如何演化。适配器模式不需要改变已有的接口,就能够 使它们协同作用。

例:

```

var googleMap = {

show: function(){

console.log( '开始渲染谷歌地图' );

}

};

var baiduMap = {

display: function(){

console.log( '开始渲染百度地图' );

}

};

var baiduMapAdapter = {

show: function(){

return baiduMap.display();

}

};

renderMap( googleMap ); // 输出:开始渲染谷歌地图

renderMap( baiduMapAdapter ); // 输出:开始渲染百度地图

```

## 总结

相信大家看完这些设计模式后心里不免会有疑惑,有些设计模式之间相似度非常高,但却被拆分为了不同的叫法(如:装饰者模式 和 代理模式,策略模式和状态模式等)。其实我觉得并不用纠结于此,设计模式本身就是为了优化代码性能,提高可读性、拓展性,更满足设计原则。只要能合理运用其中的一些代码技巧写出更好的代码,就行了。希望本系列的文章能对你的学习之路有帮助

### 系列链接

1. [16种JavaScript设计模式(上)](https://www.jianshu.com/p/455c0e34a3c0)

2. [16种JavaScript设计模式(中)](https://www.jianshu.com/p/993027963b60)

3. [16种JavaScript设计模式(下)](https://www.jianshu.com/p/0731e71475b2)

> 本文主要参考了《javascript设计模式与开发实践》一书

上一篇下一篇

猜你喜欢

热点阅读