共计 5961 个字符,预计需要花费 15 分钟才能阅读完成。
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>
正文完
发表至: javascript
2021-04-24