前言:语言只是工具,思想才是核心
今天要总结的是 策略模式
策略在开发中的应用非常广泛,所以也是非常常见且使用的设计模式。
在实际开发中,往往在实现一个功能时,有多种解决方案可行。
总结策略模式的使用场景,在想实现某个效果时,有多种不同的达成方式。这个时候就要考虑策略模式(如果你写了很多ifelse)
策略模式的应用场景:
工资计算
财务妹妹想要给技术猛男、鼓励师妹妹、冷血产品经理来统计他们本月的工资。但他们的工资计算方式不一样呀,这可咋整?
本着抽离变与不变的思路:
面对对象思路的写法:
<script>
// 策略类 定义各个角色的工资计算方式
function WageStrategy() {
}
WageStrategy.prototype.ROLE = {
IT: 'itHandsomeBoy',
ENCOURAGE: 'encourager',
MANAGER: 'productManager',
};
WageStrategy.prototype.itHandsomeBoy = function (performance) {
return (10000 + 2000) * performance;
}
WageStrategy.prototype.encourager = function (performance) {
return (9000) * performance;
}
WageStrategy.prototype.productManager = function (performance) {
return (500) * performance;
}
WageStrategy.prototype.getRoleWage = function (role, performance) {
return this[role](performance);
}
// 中间类 (发起计算的财务)【持有策略对象】
function FinancialMan(strategy) {
this.strategy = strategy;
}
FinancialMan.prototype.getWage = function (role, performance) {
return this.strategy.getRoleWage(role, performance);
};
// 运行
let financialMan = new FinancialMan(new WageStrategy());
console.log(financialMan.getWage(financialMan.strategy.ROLE.IT, 1.2));
console.log(financialMan.getWage(financialMan.strategy.ROLE.ENCOURAGE, 1));
console.log(financialMan.getWage(financialMan.strategy.ROLE.MANAGER, 1.5));
</script>
上面是模拟像Java这样基于类的语言,而js中存在很多不一样的特性,例如:函数即对象!所以以下是改进的
Js版本的策略模式。
<script>
// 策略对象,封装工资算法
let wageStrategy = {
ROLE : {
IT : 'itHansomeBoy',
ENCOURAGE : 'encourager',
MANAGER : 'productManager',
},
itHansomeBoy: function (performance) {
return (10000 + 2000) * performance;
},
encourager: function (performance) {
return (9000) * performance;
},
productManager: function (performance) {
return (500) * performance;
},
};
// 计算工资对象
let getWage= function (role, performance) {
return wageStrategy[role](performance);
}
console.log(getWage(wageStrategy.ROLE.IT, 1.2)); // 14400
console.log(getWage(wageStrategy.ROLE.ENCOURAGE, 1)); // 9000
console.log(getWage(wageStrategy.ROLE.MANAGER, 1.5)); // 750
</script>
表单验证(注册账号)
用户在填完一堆信息后【如:手机号、邮箱号、姓名、密码、验证码】,点击注册,此时应该先对每个字段进行检查,都通过后才能提交到后台。
比较猛的写法:
let register = function () {
let name, phone,
if(!name) {
return;
}else if (!phone || phone.length !== 11) {
return;
}
// do register request
}
随着需要检验的字段越来越多,那么else if的逻辑越来越重。并且,如果有个完善信息页面,同样需要用到手机号,邮箱号这些信息检测怎么复用勒?
那么,策略模式来了:
<script>
// 表单检验策略类
let checkInfoStrategy = {
phone: function (phone) {
let pass = true;
let tips = '';
if (!phone) {
pass = false;
tips = '手机号不能为空';
}
return { pass, tips };
},
email: function (email) {
let pass = true;
let tips = '';
if (!email) {
pass = false;
tips = '邮箱不能为空';
} else if (email.indexOf('@') < 0) {
pass = false;
tips = '邮箱格式不正确';
}
return { pass, tips };
}
}
// 中间者 发起表单检验
let Checker = function () {
this.cache = []; // 存放需要检验项:{策略,待检验字符}
// 添加待检查项
this.add = function (stragetyItem, beCheckInfo) {
this.cache.push({ item: stragetyItem, info: beCheckInfo });
return this;
};
// 开始检查
this.startCheck = function () {
let result = { pass : true, tips : '' };
for (let i = 0; i < this.cache.length; i++) {
let checkItem = this.cache[i];
let {pass, tips} = checkItem.item(checkItem.info);
result.pass = pass;
result.tips = tips;
if (!pass) {
break;
}
}
return result;
};
}
// 执行
let phone = '18826274139';
let email = '';
let checker = new Checker();
checker.add(checkInfoStrategy.phone, phone).add(checkInfoStrategy.email, email);
let { pass, tips } = checker.startCheck();
console.log(':::' + pass, tips); // :::false 邮箱格式不正确
</script>
其他不多说了,一定要动过。
思路就是抽离变与不变。策略类之放不同的算法/逻辑,使用中间类来协助发起策略类的使用。