將一系列算法封裝起來,爲了之後能夠互相替換使用,由策略類和context組成,context接受用戶信息,而後將請求委託給策略類
(現實生活中,咱們要去一個城市,交通方式就有:飛機、高鐵、開車、大巴等,這些方式都能到達目的地,咱們能夠根據自身需求來選擇一個策略)算法
1.策略模式利用組合、委託和多態等技術思想,能夠有效的避免許多重條件選擇語句 2.有彈性,遵照封閉/開發原則,將算法封裝在獨立的strategy中,使他易於切換、易於理解、易於擴展 3.複用方便 4.利用委託和組合來讓context擁有執行算法的能力,這也是繼承的一種更輕便的替代方案
1.會產生比較多的類和函數 2.要使用策略就要明白全部策略,違反知識最少化原則
1.封裝變化、多態、委託
1.獎金的計算
<script> // ///////////////////////////////////沒有使用策略模式///////////////////////////////////////// function cuculateBounds(leave,salary){ if(leave==="A"){ return 4*salary }else if(leave ==="B"){ return 3*salary }else{ return 2*salary } } // console.log(cuculateBounds("A",3000)) // console.log(cuculateBounds("B",3000)) // 缺點: // 一、全部邏輯都在cuculateBounds函數體裏面,要包含全部的if-else,體量龐大 // 二、缺少彈性,若是要修改獎金等級A的係數爲3.5,就要改變函數體,違反封閉開放與原則 // 三、複用性差,若是要複用則要用複製粘貼 // ///////////////////////////////////用策略模式改寫///////////////////////////////////////// // 1. 將使用算法和算法分開,使用算法的方式不會變,算法會變,因此封裝算法(封裝變化) // 2.策略類-不一樣策略返回不一樣結果(多態) var strateies={ "A":function(salary){ return 4*salary; }, "B":function(salary){ return 3*salary; }, "C":function(salary){ return 2*salary; } } // 3.context 使用算法,接收請求,不執行操做,將請求委託給策略類(委託) var caculateBounds = function(leave,salary){ return strateies[leave](salary); } console.log(caculateBounds("A",2000))
2.動畫的實現
<div id="box" style="position:absolute;width: 200px;height: 200px;background-color: cornflowerblue;"></div> <script> // /////////////////////1.策略類-封裝動畫緩動算法///////////////////// /**params * *開始位置 *要移動的距離 *消耗了多少時間 *總耗時 * */ var easing={ "linear":function(starPos,pos,time,duration){ return pos*time/duration + starPos; }, "easeIn":function( starPos,pos,time,duration){ return pos*(time/=duration)*time +starPos; } } // /////////////////////2.動畫類///////////////////////////////// // 利用定時器,沒19毫秒一幀,更新dom節點樣式 function Animate(dom){ this.dom = dom ; } // 接收4個參數 /** * 樣式 * 移動目標位置 * 執行時間 * 緩動類型 * **/ Animate.prototype.start = function(propety,pos,duration,estype){ this.propety = propety; // 開始位置 this.startPos = this.dom.getBoundingClientRect()[propety] this.endPos = pos; this.startTime = +new Date; this.endTime = this.startTime+duration; this.duraPos = pos-this.startPos; this.easing = easing[estype]; this.duration = duration; var _that = this; var timeId = setInterval(()=>{ if(_that.step()===false){ // 清空定時器 clearInterval(timeId) timeId = null; } },19) } Animate.prototype.step = function(){ // 當前時間大於結束時間,返回false var nowTime =+new Date if(nowTime>=this.endTime){ // 校訂位置 this.update(this.endPos) return false }else{ let pos = this.easing(this.startPos,this.duraPos,nowTime-this.startTime,this.duration) this.update(pos) } } Animate.prototype.update =function(val){ this.dom.style[this.propety] = val+'px' } // /////////////////////////////3.調用動畫//////////////// var dom = document.getElementById("box"); var animate = new Animate(dom); // animate.start("top",500,3000,"linear") // animate.start("left",500,2000,"easeIn") animate.start("left",500,2000,"linear") </script>
3.驗證表單
<form id="formpane"> 用戶名:<input type="text" value="" id="userName" placeholder="請輸入" /> 手機號:<input type="tel" value="" id="telphoneNum" /> 密碼:<input type="password" value="" id="userPassword" /> <button type="submit">提交</button> </form> <script> // 多規則驗證,知足條件,表單放行 /**多規則驗證,知足條件,表單放行 * 規則1:用戶名不能爲空 * 規則2:手機格式正確 * 規則3:密碼長度小於6 */ let regisform = document.getElementById("formpane"); /////////////////////////沒有策略模式寫法(個人常見寫法)////////////////// // regisform.onsubmit = function(){ // // 用戶名不能爲空 // if(regisform.userName.value.length===0){ // console.log("用戶名不能爲空") // return false // } // else if(!/(^1[3|5|8][0-9]{9}$)/.test(regisform.telphoneNum.value)){ // console.log("手機格式不正確") // return false // }else if(regisform.userPassword.value.length>6){ // // 密碼長度小於6 // console.log("密碼長度小於6") // return false // } // alert("提交成功") // } /**該寫法的啓發 * 一、表單的值能夠經過表單的dom.id(子id)例regisform.userName * 二、onsubmit函數體比較龐大,包含全部的if-else邏輯 * 三、缺少彈性,當要修改驗證規則時,須要改動內部邏輯,違反封閉開放原則 * 四、不易複用 */ // ///////////////////////////用策略模式改寫//////////////////// // 一、建立一個策略類 var stargeies = { isNameEmpty: function (value, msg) { if (value.length === 0) return msg }, isNumberTrue: function (value, msg) { if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) { return msg } }, isMinlen: function (value, min, msg) { if (value.length < min) return msg } } // 二、建立一個context的類用來接收用戶的請求 function Invalidator() { this.catchs = []; } // 添加規則 Invalidator.prototype.add = function (dom, rules, msg) { var arr = rules.split(":"); this.catchs.push(function () { let starge = arr.shift();//刪除數組第一個 let value = dom.value; arr.unshift(value);//在數組第一個插入 arr.push(msg) return stargeies[starge].apply(dom, arr); }) } // 執行規則返回結果 Invalidator.prototype.start = function () { // 這種方式遍歷,當知足條件,退出循環 for (let index = 0; index < this.catchs.length; index++) { console.log(index); let msg = this.catchs[index](); if (msg) { return msg } } } // 三、用戶調用規則,根據結果判斷是否提交表單 // var invaliFunc = function(){ // var invalidator = new Invalidator(); // invalidator.add(regisform.userName,"isNameEmpty","用戶名不能爲空"); // invalidator.add(regisform.telphoneNum,"isNumberTrue","手機格式不正確"); // invalidator.add(regisform.userPassword,"isMinlen:8","密碼長度不能小於8"); // return invalidator.start(); // } // regisform.onsubmit = function(){ // let value = invaliFunc() // if(value){ // console.log(value); // return false; // } // } // //////////////////////////////策略模式-表單驗證多規則////////////// // 添加多規則 Invalidator.prototype.adds = function (dom, arrs) { arrs.forEach(element => { let { rules, msg } = element; let arr = rules.split(":"); this.catchs.push(function () { let starge = arr.shift();//刪除數組第一個 let value = dom.value; arr.unshift(value);//在數組第一個插入 arr.push(msg) return stargeies[starge].apply(dom, arr); }) }); } var invaliFunc = function () { var invalidator = new Invalidator(); invalidator.adds(regisform.userName, [{ rules: "isNameEmpty", msg: "用戶名不能爲空" }, { rules: "isMinlen:6", msg: "用戶名不能小於6" }]); invalidator.add(regisform.telphoneNum, "isNumberTrue", "手機格式不正確"); invalidator.add(regisform.userPassword, "isMinlen:8", "密碼長度不能小於8"); return invalidator.start(); } regisform.onsubmit = function () { let value = invaliFunc() if (value) { console.log(value); return false; } } </script>
<!-- 常見的策略模式。不會有策略類來存放策略方法 --> <script> function planA(params) { console.log("A"+params) } function planB(params) { console.log("B"+params) } function planC(params) { console.log("C"+params) } // 使用高階函數的方式,參數傳入函數,而後將事件委託到策略類中執行,多態,調用這個方法傳入不一樣狀態,返回不一樣結果 function caculateBounds(func,params){ func(params) } caculateBounds(planA,"歡迎使用A策略") </script>