1、策略模式定义:
将一系列算法封装起来,为了当前能够相互替换应用,由策略类和context组成,context承受用户信息,而后将申请委托给策略类
(现实生活中,咱们要去一个城市,交通形式就有:飞机、高铁、开车、大巴等,这些形式都能达到目的地,咱们能够依据本身需要来抉择一个策略)
2、策略模式的长处
1.策略模式利用组合、委托和多态等技术思维,能够无效的防止许多重条件抉择语句2.有弹性,恪守关闭/开发准则,将算法封装在独立的strategy中,使他易于切换、易于了解、易于扩大3.复用不便4.利用委托和组合来让context领有执行算法的能力,这也是继承的一种更轻便的代替计划
3、策略模式的毛病
1.会产生比拟多的类和函数2.要应用策略就要明确所有策略,违反常识起码化准则
4、通过策略模式学习播种到什么
1.封装变动、多态、委托
5、通过例子来加深策略模式的意识
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))// 毛病:// 1、所有逻辑都在cuculateBounds函数体外面,要蕴含所有的if-else,体量宏大// 2、不足弹性,如果要批改奖金等级A的系数为3.5,就要扭转函数体,违反关闭凋谢与准则// 3、复用性差,如果要复用则要用复制粘贴// ///////////////////////////////////用策略模式改写/////////////////////////////////////////// 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("提交胜利") // } /**该写法的启发 * 1、表单的值能够通过表单的dom.id(子id)例regisform.userName * 2、onsubmit函数体比拟宏大,蕴含所有的if-else逻辑 * 3、不足弹性,当要批改验证规定时,须要改变外部逻辑,违反关闭凋谢准则 * 4、不易复用 */ // ///////////////////////////用策略模式改写//////////////////// // 1、创立一个策略类 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 } } // 2、创立一个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 } } } // 3、用户调用规定,依据后果判断是否提交表单 // 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>
6、理论场景中应用的高阶函数实现隐形的策略模式
<!-- 常见的策略模式。不会有策略类来寄存策略办法 --> <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>