javascript 設計模式之單例模式javascript
javascript 設計模式之裝飾者模式jquery
javascript 設計模式之策略模式promise
javascript 設計模式之觀察者模式markdown
狀態模式:容許一個對象在其內部狀態改變時改變它的行爲,對象看起來彷佛修改了它的類。
需求:
實現一個開關功能的電燈
代碼實現:
class Light {
constructor() {
this.state = 'off' // 默認關燈
this.button = null
}
init() {
const button = document.createElement('button')
this.button = document.body.appendChild(button)
this.button.innerHTML = '開關'
this.button.onclick = () => {
this.handleStateChange()
}
}
handleStateChange() {
if(this.state == 'off') {
console.info("開燈")
this.state = 'on'
} else if(this.state == 'on') {
console.info('關燈')
this.state = 'off'
}
}
}
const light = new Light()
light.init()
複製代碼
這個功能暫時告一段落。
但過不久產品經理要求實現這樣一種電燈:第一次按下打開弱光,第二次按下打開強光,第三次纔是關閉電燈。
你只得更改 handleStateChange 代碼爲
handleStateChange () {
if (this.state === 'off') {
console.log('弱光')
this.state = 'weakLight'
} else if (this.state === 'weakLight') {
console.log('強光')
this.state = 'strongLight'
} else if (this.state === 'strongLight') {
console.log('關燈')
this.state = 'off'
}
}
複製代碼
功能是實現了,但存在以下問題:
封裝通常是封裝對象的行爲,而不是封裝對象的狀態,可是在狀態模式中,關鍵的就是把每種狀態封裝成單獨的類,跟狀態相關的行爲都封裝在類的內部
首先先拆解出該電燈存在三種狀態:OffLightState (關燈)、WeakLightState (弱光)、StrongLightState (強光)。 編寫狀態類以下:
class OffLightState {
construct (light) {
this.light = light
}
handleStateChange () {
console.log('弱光')
this.light.setState(this.light.weakLightState)
}
}
class WeakLightState {
construct (light) {
this.light = light
}
handleStateChange () {
console.log('強光')
this.light.setState(this.light.strongLightState)
}
}
class StrongLightState {
construct (light) {
this.light = light
}
handleStateChange () {
console.log('關燈')
this.light.setState(this.light.offLightState)
}
}
複製代碼
編寫 Light 類: 採用狀態對象的形式標識當前的開關狀態,而不是以前的字符串( 'weakLight'、’strongLight‘、'off')
class Light {
construct () {
this.offLightState = new OffLightState(this)
this.weakLightState = new WeakLightState(this)
this.strongLightState = new StrongLightState(this)
this.currentState = this.offLightState // 初始化電燈狀態
this.button = null
}
init () {
const button = document.createElement('button')
this.button = document.body.appendChild(button)
this.button.innerHTML = '開關'
this.button.onclick = () => {
this.currentState.handleStateChange()
}
}
setState (newState) {
this.currentState = newState
}
}
const light = new Light()
light.init()
複製代碼
有以下優勢:
非面向對象實現的策略方式,將各個狀態定義在一個對象裏,經過對象映射的方式,以及 call 語法綁定主體類 Light
const lightState = {
'offLight': {
handleStateChange:function() {
console.log('弱光')
this.setState(lightState.weakLight)
}
},
'weakLight': {
handleStateChange:function() {
console.log('強光')
this.setState(lightState.strongLight)
}
},
'strongLight': {
handleStateChange:function() {
console.log('關燈')
this.setState(lightState.offLight)
}
}
}
class Light {
constructor () {
this.currentState = lightState.offLight // 初始化電燈狀態
this.button = null
}
init () {
console.info(this,"this")
const button = document.createElement('button')
this.button = document.body.appendChild(button)
this.button.innerHTML = '開關'
this.button.onclick = () => {
this.currentState.handleStateChange.call(this) // 經過 call 完成委託
}
}
setState (newState) {
this.currentState = newState
}
}
const light = new Light()
light.init()
複製代碼
好比實現個收藏,與取消收藏功能
import StateMachine from 'javascript-state-machine'
import $ from 'jquery'
var fsm = new StateMachine({
init: '收藏',
transitions: [
{ name: 'doStore', from: '收藏', to: '取消收藏' },
{ name: 'deleteStore', from: '取消收藏', to: '收藏' }
],
methods: {
onDoStore: function () {
console.log('收藏成功')
updateText()
},
onDeleteStore: function () {
console.log('取消收藏成功')
updateText()
}
}
})
const updateText = function () {
$('#btn1').text(fsm.state)
}
$('#btn1').on('click', function () {
if (fsm.is('收藏')) {
fsm.doStore()
} else {
fsm.deleteStore()
}
})
// 初始化
updateText()
複製代碼
promise 的 pending fulfilled rejected 是三個不一樣的狀態,而且每種狀態都有相應的行爲
import StateMachine from 'javascript-state-machine'
var fsm = new StateMachine({
init: 'pending',
transitions: [
{ name: 'resolve', from: 'pending', to: 'fulfilled' },
{ name: 'reject', from: 'pending', to: 'rejected' }
],
methods: {
onResolve: function (state, data) {
data.successCallBacks.forEach((fn) => fn())
},
onReject: function () {
data.failCallBacks.forEach((fn) => fn())
}
}
})
class MyPromise {
constructor(fn) {
this.successCallBacks = []
this.failCallBacks = []
fn(
() => {
fsm.resolve(this)
},
() => {
fsm.reject(this)
}
)
}
then(successCall, failCall) {
this.successCallBacks.push(successCall)
this.failCallBacks.push(failCall)
}
}
const loadImg = function (src) {
const promise = new MyPromise((resolve, reject) => {
const img = document.createElement('img')
img.onload = function () {
resolve(img)
}
img.onerror = function (err) {
reject(err)
}
img.src = src
})
return promise
}
var src = ' //www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'
let result = loadImg(src)
result.then(function (img) {
console.info('ok1')
})
result.then(function (img) {
console.info('ok2')
})
複製代碼
只是實現 promise 功能的一部分,但已足夠說明狀態模式的使用方式
相同點:
它們都有一個上下文、一些策略類或者狀態類,上下文把請求委託給這些類來執行
不一樣點:
策略模式:各個策略類之間是平等又平行的,它們之間沒有任何關係,因此客戶必須熟知這些策略類的做用,以便客戶本身能夠隨時主動切換算法。
狀態模式:狀態和狀態對應的行爲早已被封裝好,狀態之間的切換也早就被規定,「改變行爲」這件事發生在狀態模式的內部,對於客戶來講,不須要了解這些細節。好比電燈的開與關,是由程序切換的,不用用戶傳入狀態值。
你的點贊是對我最大的確定,若是以爲有幫助,請留下你的讚揚,謝謝!!!