在作canvas、webGL遊戲時,很深切的感受到,遊戲編程玩的都是設計模式。架構沒預先設計好,強耦合性代碼在後期維護簡直災難。javascript
大型單頁應用裏,複雜度上升到必定程度時,沒有適當的設計模式進行降耦,後續的開發也難如下手。java
而設計模式正是爲了降耦而存在。web
參考《javascript設計模式》——曾探算法
var throttle = function(fn, interval){ var _self = fn, timer, firstTime = true; return function(){ var args = arguments. _me = this; if( firstTime ){ _self.apply(_me, args); return first } if(timer){ return false; } timer = setTimeout(function(){ clearTimeout(timer); timer = null; _self.apply(_me, args); }, interval || 500); } } window.onresize = throttle(function(){ console.log(1); }, 500);
var timeChunk = function(arr, fn, count){ var obj, t; var len = ary.length; var start = function(){ for(var i = 0; i < Math.min(coutn||1, arr.length); i++){ var obj = ary.shift(); fn(obj); } } return function(){ t = setInterval(function(){ if(ary.length === 0){ return clearInterval(t); } start(); }, 200); }; };
var addEvent = function(elem, type, handler){ if(window.addEventListener){ addEvent = function(elem, type, handler){ elem.addEventListener(type, handler, false); } } else if(window.addachEvent){ addEvent = function(elem, type, handler){ elem.attachEvent('on' + type, handler); } }
}編程
定義:保證類有且僅有一個實力,並提供全局訪問接口。canvas
私有變量加下劃線 var _a = 1;
把建立單例和管理單例的職責分開來:設計模式
var getSingle = function(fn){ var result; return function(){ return result || (result = fn.apply(this, arguments)); } } var createLayer = function(){ var div = document.createElement('div'); document.body.appendChild(div); } var createSingleCreateLayer = getSingle(createLayer); document.getElementById('#test').onclick = () => { createSingleCreateLayer(); }
定義:封裝一系列算法,並使其能夠相互替換緩存
計算工資Demo:性能優化
var strategies = { 'S': function(salary){ return salary * 4; }, 'A': function(salary){ return salary * 3; } } var calculateBonus = (level, salary) => { return strategies[level](salary); }
表單添加多種校驗規則:架構
/*--------------- Strategies --------------*/ var strategies = { isNotEmpth: (value, errorMsg) => { if(value == ''){ return errorMsg; } }, minLength: (value, length,errorMsg) => { if(value.length < length){ return errorMsg; } } } /*---------------- Validator ---------------*/ var Validator = () => { this.cache = []; } Validator.prototype.add = (dom, rules) => { var self = this; for(var i = 0; rule; rule = rules[i++]){ ((rule) => { var strategyAry = strategy.split(':'); var errorMsg = rule.errorMsg; self.cache.push(function(){ var strategy = strategyAry.shift(); strategyAry.unshift(dom.value); strategyAry.push(errorMsg); return strategies[strategy].apply(dom, strategyAry); }); })(rule); } }; Validator.prototype.start = () => { for(var i = 0; validatorFunc; validatorFunc = this.cache[i++]){ var errorMsg = validatorFunc(); if( errorMsg ){ return errorMsg; } } } /*-------------- 客戶端調用 ------------*/ var registerForm = document.getElementById('registerForm'); var validataFunc = () => { var validator = new Validator(); validator.add(registorForm.username, [{ strategy: 'isNotEmpty', errorMsg: '用戶名不能爲空' },{ strategy: 'minLength', errorMsg: ‘最下長度爲6’ }]); validator.add(registorForm.password, [{ strategy: 'minLength', errorMsg: '最小長度' }]) var errorMsg = validator.start(); return errorMsg; } registerForm.onsubmit = () => { var errorMsg = validataFunc(); if(errorMsg){ alert(errorMsg); return false; } }
爲一個對象提供一個代用品或者佔位符,以便控制它的訪問
面向對象設計原則——單一職責原則。面向對象設計鼓勵將行爲分佈到細粒度的對象之中。
大量計算時加入代理做爲緩存,異步請求時同理可用緩存:
var mult = () => { var a = 1; for(var i = 0, l = arguments.length; i < l; i++){ a = a * arguments[i]; } return a; } var proxyMult = (() => { var cache = {}; return () => { var args = Array.prototype.join.call(arguments, ','); if( args in cache ){ return cache[args]; } return cache[args] = mult.apply(this, arguments); } })();
var mult = () => { var a = 1; for(var i = 0, l = arguments.length; i < l; i++){ a = a * arguments[i]; } return a; } var plus = () => { var a = 0; for(var i = 0, l = arguments.length; i < l; i++){ a = a + arguments[i]; } return a; } var createProxyFactory = (fn) => { var cache = {}; return () => { var args = Array.prototype.join.call(arguments, ','); if(args in cache){ return cache[args]; } return cache[args] = fn.apply(this, arguments); } }
迭代器模式指提供一種方法順序訪問一個聚合對象的各個元素,又不暴露該對象的內部表示。
通用外部迭代器:
var Iterator = (obj) => { var current = 0; var next = () => { ++current; } var isDone = () => { return current >= obj.length; } var getCurrItem = () => { return obj[current]; } return { next: next, isDone: isDone, getCurrItem: getCurrItem } }
var event = { clientListh: [], listen: function(key, fn){ if(!this.clientListh[key]){ this.clientList[key] = []; } this.clientList[key].push(fn); }, trigger: function(){ var key = Array.prototype.shift.call(arguments), fns = this.clientList[key]; if(!fns || fns.length === 0){ return false; } for(var i = 0; fn; fn = fns[i++]){ fn.apply(this.arguments); } } } var installEvent = function(obj){ for(var i in event){ obj[i] = event[i]; } }; var salesOffices = {}; installEvnet(salesOffices); salesOffices.listen('squareMeter88', function(price){ console.log('price': + price); }) salesOfffices.trigger('squareMeter88', 20000);
發佈——訂閱模式能夠很大程度下降耦合性,但濫用也會形成背後邏輯混亂,且浪費內存。
主要是回調函數的的面向對象的替代品
沒看懂命令模式有什麼意義
var commandStack = []; document.onkeypress = (ev)=>{ var keyCode = ev.keyCode, command = makeCommand(Ryu, commands[keyCode]); if(command){ command(); commandStack.push(command); } } $('#replay').onclick = ()=>{ var command; while(command = commandStack.shift()){ command(); } }
var closeDoorCommand = { excute: ()=> { console.lg('close door'); } } var openPcCommand = { excute: ()=> { console.log('open pc'); } } var MacroCommand = ()=> { return { conmandList: [], add: (command)=>{ this.commandList.push(command); }, execute: ()=>{ for(var i = 0, command; command = this.commandsList[i++]; ){ command.execute(); } } } }
相似命令模式的增強版,也是看不懂深層意義
遍歷文件夾
/************ Folder ****************/ var Folder = (name)=>{ this.name = name; this.parent = null; this.files = []; }; Folder.prototype.add = (file)=> { file.parent = this; this.files.push(file); } Folder.prototype.scan = ()=>{ console.log('Begin scan: ' + this.name); for(var i = 0, file = this.files; file = files[i++]; ){ file.scan(); } } Folder.prototype.remove = ()=>{ if(!this.parent){ return; } for(var files = this.parent.files, l = files.length-1; l >= 0; l--){ var file = files[l]; if(file === this){ files.splice(l, 1); } } } /************ File ****************/ var File = (name)=>{ this.name = name; this.parent = null; } File.prototype.add = ()=>{ throw new Error('Can not add file under file'); } File.prototype.scan = ()=>{ console.log('Begin Scan: ' + this.name); } File.prototype.remove = ()=>{ if(!this.parent){ return; } for(var files = this.parent.files, l = files.length-1; l >= 0; l--){ var file = files[l]; if(file == this);{ file.splice(l, 1); } } }
基於繼承的設計模式
模板方法模式友抽象父類和具體實現的子類組成。父類封裝了子類的算法框架,子類經過集成抽象類,也繼承了整個算法框架。
var Bevrage = function(){} Beverage.prototype.boilWater = function(){ console.log('把水煮沸'); } Beverage.prototype.brew = function(){ throw new Error('Class brew musth be rewrited'); } .... Beverage.prototype.addCondiments = function(){ throw new Error('adCondiments must be rewrited'); } Beverage.prototype.customerWantsCondiments = function(){ return true; } Beverage.prototype.init = function(){ this.boilWater(); this.brew(); .... if(this.customerWantsCondiments()){ this.addCondiments(); } } var CoffeeWithHook = function(){}; CoffeeWithHook.prototype = new Beverage(); CoffeeWithHook.prototype.brew = function(){ console.log('brew coffee with water'); }; CoffeeWithHook.prototype.customerWantsCondiments = function(){ return widow.confirm('須要調料嘛?'); } var coffeeWithHook = new CoffeeWithHook(); coffeeWithHook.init();
高階函數能夠更方便的實現上面的demo...
用於性能優化,核心是運用共享技術來支持大量細粒度的對象。
通用對象池的實現
var objectPoolFactory = (createObjFn)=>{ var objectPool = []; return{ create: function(){ var obj = objectPool.length === 0 ? createObjFn.apply(this, arguments) : objectPool.shift(); return obj; }, recover: (obj){ objectPool.push(obj); } } }
用來重構代碼挺方便的。
把不一樣功能函數包裝成鏈式節點再調用。
var order500 = function(orderType, pay, stock){ if(orderType == 1 && pay == true){ conosle.log('500, 100優惠券') } else{ return 'nextSuccessor'; // 把請求日後傳遞 } } var order200 = function(orderTYPE, pay, stock){ if(orderType == 2 && pay ==true){ console.log('200, 50優惠券'); } else{ return 'nextSuccessor'; } } var orderNormal = function(orderType, pay, stock){ if(stock > 0){ console.log('普通購買,無優惠券'); } else{ console.log('庫存不足'); } } //職責鏈包裝函數 //Chain.prototype.setNextSuccessor 指定在鏈中的下一個結點 //Chain.prototype.passRequest 請求傳遞給某個結點 var Chain = function(fn){ this.fn = fn; this.successor = null; } Chain.prototype.setNextSuccessor = function(successor){ return this.successor = seccussor; } Chain.prototype.passRequest = function(){ var ret = this.fn.apply(this, arguments); if(ret === 'nextSuccessor'){ return this.successor && this.seccessor.passRequest.apply(this.successor, arguments); } return ret; } //將訂單函數包裝進職責鏈 var chainOrder500 = new Chain(order500); var chainOrder200 = new Chain(order200); var chainOrderNormal = new Chain(orderNormal); chainOrder500.setNextSuccessor(chainOrder200); ChainOrder200.setNextSuccessor(chainOrderNormal); //Test] chainOrder500.pasRequest(1, true, 500);
我的感受有點像代理模式.用一箇中介對象,來處理其餘對象的時間,以實現解耦的目的。
但缺點也很明顯,當系統複雜到必定程度時,中介者對象慢慢會變成一個難以維護的對象
動態的給類添加職責