上一回聊了聊組合模式(Composite),用組合模式模擬了個圖片庫,聊了遞歸。
介一回聊狀態模式(State),官方描述容許一個對象在其內部狀態改變時改變它的行爲。略抽象,不過看了代碼會以爲比較簡單,直接看代碼先。javascript
狀態模式中引入了抽象狀態類和具體狀態類,這裏會用到以前講過的接口模式,不清楚的盆友能夠看系列05,這個例子是我根據一段PHP的狀態模式代碼改的JS版本,以下:前端
var c = console,d = document; window.onload = function(){ // 定義了一個state接口,倆方法handle,display var State = new Interface("State",["handle","display"]); // 這裏的Context是環境類,或者稱爲上下文類,是擁有多種狀態的對象。 var Context = function(state){ // 狀態變化的屬性 var _state = null; var _self = this; // 這裏是設置狀態對象 this.setState = function(state){ _self._state = state; } // 調用狀態對象的方法 this.request = function(){ _self._state.display(); _self._state.handle(_self); } this.setState(state); } // 具體狀態類,抽象狀態類的子類 var StateA = function(){ // 檢測接口,不明白的童鞋看系列05 Interface.ensureImplements(this,State); } // 狀態類的實現 StateA.prototype = { constructor:StateA, // 這裏的context指向的是Context handle:function(context){ // 設置爲其餘狀態 context.setState(new StateB()); }, // 具體實現的方法 display:function(){ c.log('StateA'); } } // StateB跟StateA同樣,只是狀態設置不一樣 var StateB = function(){ Interface.ensureImplements(this,State); } StateB.prototype = { constructor:StateB, handle:function(context){ context.setState(new StateC()); }, display:function(){ c.log('StateB'); } } // StateC跟StateB同樣,只是狀態設置不一樣 var StateC = function(){ Interface.ensureImplements(this,State); } StateC.prototype = { constructor:StateC, handle:function(context){ context.setState(new StateA()); }, display:function(){ c.log('StateC'); } } // 測試代碼 var o = new Context(new StateB()); o.request(); // StateB o.request(); // StateC o.request(); // StateA o.request(); // StateB o.request(); // StateC o.request(); // StateA }
之因此把這個例子改爲JS版本,是由於這個例子比較簡單,直觀。在實際使用時,在一個狀態類中可能包含多個業務方法,若是在具體狀態類中某些業務方法的實現徹底相同,能夠將這些方法移至抽象狀態類,實現代碼的複用。vue
狀態模式在工做流或遊戲等各類系統中應用比較普遍,下面的例子是一個簡單的訂單審批流程,根據一段Java的狀態模式代碼改的JS版本,以下:java
var c = console,w = window; w.onload = function(){ // 業務申請方 function Obj() { // 申請方 this.obj = ''; // 日期 this.sDate = ''; // 金額 this.aMount = ''; // 結果 this.res = ''; } // 跟上一個例子同樣,Context狀態管理類 var Context = function (s) { this.state = null; this.run = function (s) { this.state = s; }; this.run(s); } // 第一層級審覈 var StateA = function (o) { // 這一堆就是一個簡單交互 var reply = w.prompt('贊成請按1,不一樣意請按任意鍵'); var res = reply == 1 ? '贊成' : '不一樣意'; var state; o.res = res; // 一堆打印信息 c.log( '平臺審覈中...' + '申請方:' + o.obj + ' ' + '日期:' + o.sDate + ' ' + '金額:' + o.aMount + ' ' + '平臺審覈結果:' + o.res ); // 判斷是否贊成,若是不一樣意直接走Notice提示不一樣意 if (reply == 1) { // 這裏就是走第二層級 state = new StateB(o); } else { state = new Notice(o); } return state; } // 第二層級審覈,跟第一層級差很少 var StateB = function (o) { var reply = w.prompt('贊成請按1,不一樣意請按任意鍵'); var res = reply == 1 ? '贊成' : '不一樣意'; var state; o.res = res; c.log( '商家審覈中...' + '申請方:' + o.obj + ' ' + '日期:' + o.sDate + ' ' + '金額:' + o.aMount + ' ' + '商家審覈結果:' + o.res ); // 由於是最終審覈,因此直接走Notice提示 state = new Notice(o); return state; } // Notice通知類,打印信息 var Notice = function (o) { c.log('申請方:' + o.obj + '的流程結束,審覈結果爲:' + o.res); } // 測試 var o = new Obj(); o.obj = '大衛'; o.sDate = '聖誕節'; o.aMount = 250; var req = new Context(new StateA(o)); req.run(); };
這個例子跟上一個例子都是狀態模式的一個很好體現,這個例子更貼近實際開發,
申請方提交訂單,平臺訂單審覈,審覈經過更改狀態爲審覈經過,而後繼續商家中心審覈,經過與不經過都流程結束,直接調用提示類提示結果。react
有限狀態機(Finite-state machine)是一個很是有用的模型,能夠模擬世界上大部分事物。這個是官方說法,簡單說,她有三個特徵:
1,狀態總數(state)是有限的。
2,任一時刻,只處在一種狀態之中。
3,某種條件下,會從一種狀態轉變(transition)到另外一種狀態。
直接代碼吧,很直觀的,根據網上的交通燈例子改的,以下::canvas
var c = console,d = document; window.onload = function(){ var Light = function() { // 設置默認狀態,關燈 this.currentState = State.off; this.lightSwitch = null; }; Light.prototype.run = function() { var _self = this; // 這裏是開關 var lightSwitch = d.createElement('button'); // 這個canvas就當是一盞燈了 var cvs = d.createElement('canvas'); cvs.width = '200'; cvs.height = '200'; cvs.style.backgroundColor = 'lightblue'; cvs.style.borderRadius = '50%'; cvs.style.display = 'block'; // 初始值是開燈 lightSwitch.innerHTML = '開燈'; // Dom方法appendChild沒什麼好說的 this.lightSwitch = d.body.appendChild(lightSwitch); this.cvs = d.body.appendChild(cvs); // 開關的點擊事件 this.lightSwitch.onclick = function() { // 委託請求給State狀態機,這裏分兩步走,第一步是_self.currentState,第二步是btnPress,call用來指向將做用域指向自己 _self.currentState.btnPress.call(_self); }; }; // 這裏就是多種狀態間的切換,這裏只寫了兩種,開關燈 var State = { off: { btnPress: function() { this.lightSwitch.innerHTML = '關燈'; this.cvs.style.display = 'none'; this.currentState = State.on; } }, on: { btnPress: function() { this.lightSwitch.innerHTML = '開燈'; this.cvs.style.display = 'block'; this.currentState = State.off; } } }; // 測試代碼 var light = new Light(); light.run(); };
這裏就是多種狀態間的切換,這裏只寫了兩種,開關燈,好玩兒一點能夠換canvas的顏色,作變亮變暗的狀態。前端框架
裝個逼,雖然最近熱映的《尋龍訣》好看,仍是要推薦一個阿湯哥的老電影《遺忘戰境》~~app
這一回聊的狀態模式,有限狀態機,狀態模式能夠容許客戶端改變狀態的轉換行爲,而狀態機則是可以自動改變狀態~。
下面的內容,聊一下狀態管理,這裏拿一個極具審美(由於做者常常提審美^_^)的JS庫Vue.js的官方例子來講。框架
Vue官方解釋是集中管理狀態更易於理解狀態將怎樣變化。組件仍然能夠擁有和管理它的私有狀態。看過上面的例子,看這個應該很好理解,繼續寫:函數
// 這裏的store裏面放了全部的action var store = { state: { message: 'Hello!' }, // 這裏的action則用來修改store的狀態state actionA: function () { this.state.message = 'action A triggered' }, // 這裏跟上面的例子很像 actionB: function () { this.state.message = 'action B triggered' } } // 這個new Vue暫時不用管,簡單的解釋下吧,經過構造函數Vue建立一個Vue的根實例 var vmA = new Vue({ data: { privateState: {}, sharedState: store.state } }) var vmB = new Vue({ data: { privateState: {}, sharedState: store.state } })
這是vue.js官網上的一個例子,最近很火的框架react,vue.js在說flux單向數據流,其實就是在維護狀態。
這裏囉嗦一下,有盆友建議說聊一下AngularJS,在系列04裏有聊過一點點ng1.x的源碼,也模擬了一下,而且說過能夠的話,分享讀過的Angularjs源碼段子。介於前端框架風起雲涌,其實,對Angular有興趣的盆友,能夠直接從Angular2開始,若是是學習源碼的話,Vue.js的源碼讀起來會更有美感(由於做者反覆提審美^_^)~~
這一回,主要聊了狀態模式,有限狀態機,介紹了下Vue.js這個庫。
下一回,聊一聊JS的鏈式調用,沒錯,確定會模擬框架,庫什麼的。
客觀看完點個贊,推薦推薦唄,嘿嘿~~
注:此係飛狐原創,轉載請註明出處