场景:去某个地方旅游,根据实际情况选择出行的路线。
解决方案:
- 经济充裕的话,可以选择坐飞机。
- 经济差不多的话,可以选择坐大巴。
- 经济不充裕的话,可以选择骑自行车。
策略模式:
- 概念:定义一系列的算法,把它们分别单独封装起来,使他们可以相互替换。
- 目的:将算法的使用和算法的实现分离开来。
- 组成:一组策略类,封装了具体的算法,负责具体的计算过程。一个环境类,接收客户的请求,随后把请求委托给环境类。(关键:说明了这个环境类要持有策略类的引用,才能实现委托)
应用举例:计算年终奖
- 年终奖:根据员工的工资基数和年底绩效情况发放。
- 绩效S:工资*4
- 绩效A:工资*3
- 绩效B:工资*2
- 分析:找出不变的部分和可变的部分。
- (1)不管是绩效S,绩效A,还是绩效B也好,员工都有对应的绩效,因此从一个大的范围,泛谈的话,员工都有绩效。
- (2)不管是工资高还是工资低,员工都有自己的工资。
- (3)根据第一和第二条可以知道,不管是年终奖多还是年终奖少,员工都有年终奖。因此最后得出:不变的总部分是年终奖大家都有,即大家都有年终奖=绩效*工资
- (4)可变的部分:深入具体每个人的绩效,大家都是不同的;深入具体每个人的工资,大家都是不同的;深入具体每个人的年终奖,大家都是不同的。
- 理解思路:提取出大家相似的部分单独隔离起来,再把大家各自具体不同的部分各自按各自的具体算法封装起来。(js当中一般就是函数的方式)
代码实现
利用if条件语句,实现年终奖的计算:
let getBonus=function(performance,salary){
if(performance==='S'){
return salary*4;
}else if(performance==='A'){
return salary*3;
}else if(performance=='B'){
return salary*2;
}
}
const S_4000=getBonus('S',4000);
const S_5000=getBonus('S',5000);
const A_2000=getBonus('A',2000);
const A_3000=getBonus('A',3000);
console.log(S_4000,S_5000,A_2000,A_3000);
面向对象方式实现策略模式:
class PerformanceS{
getBonus(salary){
return salary*4;
}
}
class PerformanceA{
getBonus(salary){
return salary*3;
}
}
class PerformanceB{
getBonus(salary){
return salary*2;
}
}
class Bonus{
constructor(){
this.salary=null;
this.strategy=null;
}
setSalary(salary){
this.salary=salary;
}
setStrategy(strategy){
this.strategy=strategy;
}
getBonus(){
return this.strategy.getBonus(this.salary);
}
}
const bonus=new Bonus();
const performanceS=new PerformanceS();
const performanceA=new PerformanceA();
bonus.setSalary(4000);
bonus.setStrategy(performanceS);
let bns=bonus.getBonus();
console.log(bonus);
javascript实现策略模式:
const strategies={
"S":function(salary){return salary*4 },
"A":function(salary){return salary*3},
"B":function(salary){return salary*2}
};
const getBonus=function(strategy,salary){
return strategies[strategy](salary);
};
应用举例:表单校验
<body>
<form id="registerForm">
<input id="username"/>
<input id="password"/>
<input id="phoneNumber"/>
<input type="submit"/>
</form>
<script src="./表单校验.js"></script>
</body>
/**
* 策略模式:
* 变化部分:策略对象,表单的校验有许多不同的规则
* 不变的部分:
*/
let strategy = {
isNonEmpty: function (value, errorMsg) {
if (value === '') {
return errorMsg;
}
},
minLength: function (value, length, errorMsg) {
if (value.length < length) {
return errorMsg;
}
},
isMobile: function (value, errorMsg) {
if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
return errorMsg;
}
}
}
//获取form表单
let registerForm = document.getElementById('registerForm');
/**registerForm.onsubmit <Function>
* 任务:点击提交按钮时,启动校验函数,如果校验函数返回值errorMsg不为空,就输出这个errorMsg,同时阻止表单提交。
*/
registerForm.onsubmit = function () {
let errorMsg = validaFunc();
if (errorMsg) {
alert(errorMsg);
return false; //阻止表单提交
}
}
/**validataFunc <Function>
* 任务:创建一个校验器,用于添加校验规则,同时启动校验器,返回校验器校验结果errorMsg
*/
let validataFunc = function () {
let validator = new Validator();
validator.add(registerForm.userName, 'isNonEmpty', '用户名不能为空');
validator.add(registerForm.password, 'minLength:6', '密码长度不能少于6位');
validator.add(registerForm.phoneNumber, 'isMobile', '手机号码格式不正确');
let errorMsg = validator.start();
return errorMsg;
};
/**Validator <Constructor>
* 角色:Context类
* 作用:负责接收用户的请求,并委托给strategy对象。
*/
let Validator = function () {
this.cache = []; //保存校验规则
}
/**Validator.prototype.add <Function>
* 作用:添加规则
* 参数:
* dom <Object> 需要添加规则的DOM节点
* rule <String> 需要添加的规则名称
* errorMsg <String> 校验错误提示消息
*/
Validator.prototype.add = function (dom, rule, errorMsg) {
let arr = rule.split(':'); //将strategy和参数分开来 'isMobile:6' 结果获得[strategy,6]
/**validate <Function>
*任务:收集校验参数,然后调用策略对象,并传入参数。
*/
let validate = function () {
let strategy = arr.shift(); //从[strategy,6]中获取strategy
arr.unshift(dom.value); //将表单字段的值放入[6,]中,结果获的[dom.value,6]
arr.push(errorMsg); //再将需要提示的错误消息放入数组arr中,结果获得[dom.value,6,errorMsg]
return strategies[strategy].apply(dom, arr);
}
this.cache.push(validate); //将校验规则添加进数组当中
};
/**Validator.prototype.start <Function>
* 任务:循环校验器中的保存的校验规则,对每一个校验规则启动校验,然后如果校验不过,有返回消息,就返回。
* 自我看法:这个函数的作用感觉只是起到一个遍历的作用,调用后遍历校验器validator中的cache属性(数组),然后
* 对这个数组中的每一个ValidatorFunc进行调用,获取msg,不为空,就返回msg
*/
Validator.prototype.start = function () {
for (let i = 0; ValidatorFunc; ValidatorFunc = this.cache[i++]) {
let msg = ValidatorFunc(); //启动校验,并获取校验返回的消息
if (msg) { //如果这个消息存在,说明肯定没有验证成功
return msg;
}
}
}