16種JavaScript設(shè)計模式(下)

## 簡介

緊接[上文(地址)](http://www.itdecent.cn/p/993027963b60),我們繼續(xù)介紹以下幾種設(shè)計模式

* 模板方法模式

* 享元模式

* 責任鏈模式

* 中介者模式

* 裝飾者模式

* 狀態(tài)模式

* 適配器模式

#### 模板方法模式

定義:基于繼承的設(shè)計模式,在父類中定義需要實現(xiàn)的方法,并定義好方法的執(zhí)行邏輯,子類只需實現(xiàn)對應(yīng)方法即可

簡介:模板方法模式是一種只需通過繼承就可以實現(xiàn)的簡單模式。這種模式在前端框架中十分常見,vue、react的組件定義都用到了該模式。大家思考下為什么我們在vue組件中定義的生命周期函數(shù)會按照給定的順序執(zhí)行呢?通過下面的簡單示例來了解下。

例:

```

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

? ? this.config = config

}

// 定義需要實現(xiàn)的方法

Vue.prototype.created = function () {}

Vue.prototype.mounted = function () {}

Vue.prototype.destoryed = function () {}

// 定義執(zhí)行邏輯

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()

```

#### 享元模式

定義:將對象屬性劃分為內(nèi)、外兩種屬性,共享內(nèi)部狀態(tài)節(jié)約內(nèi)存

簡介:享元模式是一種用于性能優(yōu)化的模式,避免創(chuàng)建大量類似的對象,占用大量內(nèi)存。

例:

```

var Hero = function (name) {

? ? this.name = name // 內(nèi)部狀態(tài)

}

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]; // 外部狀態(tài)

? ? GayLun.show()

}

```

#### 責任鏈模式

定義:將一系列處理方法連成鏈條,請求在這個鏈條中傳遞,直到遇到一個可以處理它的方法。

簡介:如果大家接觸過node開發(fā),可能會比較好理解這個模式。node開發(fā)中我們會定義許多中間件依次掛載到node實例上。當服務(wù)器收到請求時請求回依次通過這些中間件方法,這些方法收到請求對象時會判斷并處理該請求,然后傳給下一個方法。

```

var ming = function(next, subject){

? ? console.log(next);


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

? ? ? ? console.log( '這題我會是2' )

? ? } else {

? ? ? ? next(subject) //我不知道下一個節(jié)點是誰,反正把請求往后面?zhèn)鬟f

? ? }

};

var zhang = function(next, subject){

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

? ? ? ? console.log( '這題我會是0' )

? ? } else {

? ? ? ? next(subject) //我不知道下一個節(jié)點是誰,反正把請求往后面?zhèn)鬟f

? ? }

};

var wang = function(next, subject){

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

? ? ? ? console.log( '這題我會是1' )

? ? } else {

? ? ? ? next(subject) //我不知道下一個節(jié)點是誰,反正把請求往后面?zhèn)鬟f

? ? }

};

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')

```

#### 中介者模式

定義:解除對象與對象之間的緊耦合關(guān)系。增加一個中介者對象后,所有的 相關(guān)對象都通過中介者對象來通信。

簡介:中介者使各對象之間耦合松散,而且可以獨立地改變它們之間的交互。中介者

模式使網(wǎng)狀的多對多關(guān)系變成了相對簡單的一對多關(guān)系。中介者也被稱為調(diào)停者,我們想象一下機場的指揮塔,如果沒有指揮塔的存在,每一架飛機 要和方圓 100 公里內(nèi)的所有飛機通信,才能確定航線以及飛行狀況,后果是不可想象的?,F(xiàn)實中 的情況是,每架飛機都只需要和指揮塔通信。指揮塔作為調(diào)停者,知道每一架飛機的飛行狀況, 所以它可以安排所有飛機的起降時間,及時做出航線調(diào)整。

```

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)

```

#### 裝飾者模式

定義:給對象動態(tài)地增加職責的方式稱為裝 飾者(decorator)模式

簡介:裝飾者模式能夠在不改 變對象自身的基礎(chǔ)上,在程序運行期間給對象 動態(tài)地添加職責。跟繼承相比,裝飾者是一種 更輕便靈活的做法(超類和子類之間存在強耦合性,當超類改變時,子類也會隨之 改變)

例:在飛機大戰(zhàn)游戲中,我們可以吃到一些額外的的武器包來強化我們的小飛機

```

var Plane = function () {

? ? this.plane = plane;

}

Plane.prototype.fire = function () {

? ? console.log('發(fā)射子彈');

}

var MissileDecorator = function (plane) {

? ? this.plane = plane;

}

MissileDecorator.prototype.fire = function () {

? ? this.plane.fire();

? ? console.log('兩側(cè)發(fā)射導彈');

}

var plane = new Plane();

plane = new MissileDecorator(plane);

plane.fire();

```

#### 狀態(tài)模式

定義:允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為,對象看起來似乎修改了它的類。

簡介:狀態(tài)模式的關(guān)鍵是區(qū)分事物內(nèi)部的狀態(tài),事物內(nèi)部狀態(tài)的改變往往會帶來事物的行為改變。

相對于策略模式來說狀態(tài)模式中,狀態(tài) 和狀態(tài)對應(yīng)的行為是早已被封裝好的,狀態(tài)之間的切換也早被規(guī)定完成,“改變行為”這件事情 發(fā)生在狀態(tài)模式內(nèi)部。對客戶來說,并不需要了解這些細節(jié)。這正是狀態(tài)模式的作用所在。

例:電燈開關(guān)

```

var OffLightState = function (light) {

? ? this.light = light;

};

OffLightState.prototype.buttonWasPressed = function () {

? ? console.log('開燈'); // offLightState 對應(yīng)的行為

? ? this.light.setState(this.light.onLightState); // 切換狀態(tài)到onLightState

};

// WeakLightState:

var OnLightState = function (light) {

? ? this.light = light;

};

OnLightState.prototype.buttonWasPressed = function () {

? ? console.log('關(guān)燈'); // onLightState 對應(yīng)的行為

? ? this.light.setState(this.light.offLightState); // 切換狀態(tài)到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() // 關(guān)燈

```

#### 適配器模式

定義:通過包裝函數(shù),統(tǒng)一接口定義

簡介:適配器模式主要用來解決兩個已有接口之間不匹配的問題,它不考慮這些接口是怎樣實 現(xiàn)的,也不考慮它們將來可能會如何演化。適配器模式不需要改變已有的接口,就能夠 使它們協(xié)同作用。

例:

```

var googleMap = {

show: function(){

console.log( '開始渲染谷歌地圖' );

}

};

var baiduMap = {

display: function(){

console.log( '開始渲染百度地圖' );

}

};

var baiduMapAdapter = {

show: function(){

return baiduMap.display();

}

};

renderMap( googleMap ); // 輸出:開始渲染谷歌地圖

renderMap( baiduMapAdapter ); // 輸出:開始渲染百度地圖

```

## 總結(jié)

相信大家看完這些設(shè)計模式后心里不免會有疑惑,有些設(shè)計模式之間相似度非常高,但卻被拆分為了不同的叫法(如:裝飾者模式 和 代理模式,策略模式和狀態(tài)模式等)。其實我覺得并不用糾結(jié)于此,設(shè)計模式本身就是為了優(yōu)化代碼性能,提高可讀性、拓展性,更滿足設(shè)計原則。只要能合理運用其中的一些代碼技巧寫出更好的代碼,就行了。希望本系列的文章能對你的學習之路有幫助

### 系列鏈接

1. [16種JavaScript設(shè)計模式(上)](http://www.itdecent.cn/p/455c0e34a3c0)

2. [16種JavaScript設(shè)計模式(中)](http://www.itdecent.cn/p/993027963b60)

3. [16種JavaScript設(shè)計模式(下)](http://www.itdecent.cn/p/0731e71475b2)

> 本文主要參考了《javascript設(shè)計模式與開發(fā)實踐》一書

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容