很快,迎来了 JavaScript 设计模式系列的第二篇 —— 策略模式 ...
策略模式定义: 定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换
策略模式一般由两部分组成:
策略模式广泛应用于程序研发中,当出现需要根据不同的前置条件执行不同的算法得到结果时,使用策略模式可以让你的代码更加优雅
怎么?不信?那就上点代码让你感受一下 💩 山的力量!
假设一个函数负责 Consul (服务发现)和 LB (负载均衡) 这里 Consul 函数就是 Context,各种 LB 算法就是策略组 传入服务唯一标识和负载均衡算法 返回服务器实例 IP 地址 如想了解 LB 相关知识,可以看看这篇文章 [深入浅出LB]手把手带你实现一个负载均衡器
function consul(serviceId, algorithm) {
if (algorithm === 'random') {
// random flow
// ...
return 'xxx.xxx.xxx.xxx';
} else if (algorithm === 'weightedRoundRobin') {
// weightedRoundRobin flow
// ...
return 'xxx.xxx.xxx.xxx';
} else if (algorithm === 'ipHash') {
// ipHash flow
// ...
return 'xxx.xxx.xxx.xxx';
} else if (algorithm === 'urlHash') {
// urlHash flow
// ...
return 'xxx.xxx.xxx.xxx';
} else if (algorithm === 'leastConnection') {
// leastConnection flow
// ...
return 'xxx.xxx.xxx.xxx';
} else if (algorithm === 'fair') {
// fair flow
// ...
return 'xxx.xxx.xxx.xxx';
}
}
可以发现,这段代码存在着一些明显的问题
针对以上问题,我们可以利用策略模式加以优化
function random(serviceId) {
// random flow
// ...
return 'xxx.xxx.xxx.xxx';
}
function weightedRoundRobin(serviceId) {
// weightedRoundRobin flow
// ...
return 'xxx.xxx.xxx.xxx';
}
function ipHash(serviceId) {
// IPHash flow
// ...
return 'xxx.xxx.xxx.xxx';
}
function urlHash(serviceId) {
// URL Hash flow
// ...
return 'xxx.xxx.xxx.xxx';
}
function leastConnection(serviceId) {
// leaseConnection flow
// ...
return 'xxx.xxx.xxx.xxx';
}
function fair(serviceId) {
// fair flow
// ...
return 'xxx.xxx.xxx.xxx';
}
const ALGORITHM = {
RANDOM: 'random',
WEIGHTED_ROUND_ROBIN: 'weightedRoundRobin',
IP_HASH: 'ipHash',
URL_HASH: 'urlHash',
LEAST_CONNECTION: 'leastConnection',
FAIR: 'fair',
};
const ALGORITHM_MAP = {
[ALGORITHM.RANDOM]: random,
[ALGORITHM.WEIGHTED_ROUND_ROBIN]: weightedRoundRobin,
[ALGORITHM.IP_HASH]: ipHash,
[ALGORITHM.URL_HASH]: urlHash,
[ALGORITHM.LEAST_CONNECTION]: leastConnection,
[ALGORITHM.FAIR]: fair,
};
function consul(serviceId, algorithm) {
return ALGORITHM_MAP[algorithm](serviceId);
}
// 粗糙的表单校验
let loginFrom = document.getElementId("loginFrom")
loginFrom.onsubmit = function (e) {
const username = document.getElementId("username")
const pwd = document.getElementId("pwd")
const mobile = document.getElementId("mobile")
if (username === '') {
alert("用户名不可为空")
return false
}
if (pwd.length < 6) {
alert("密码长度不能少于6位")
return false
}
if (!/^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/.test(mobile)) {
alert("手机号码格式不正确")
return false
}
}
Context:validate 策略组:strategy
// 使用策略模式优化
const strategy = {
isEmpty: function ({ value }, errMsg) {
if (value === '') {
return errMsg;
}
},
isMobile: function ({ value }, errMsg) {
if (
!/^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/.test(value)
) {
return errMsg;
}
},
isLongerThanMinLength: function ({ value, len }, errMsg) {
if (value.length < len) {
return errMsg;
}
},
};
class Validator {
constructor() {
this.validateItems = [];
}
add(params, strategyKey, errMsg) {
this.validateItems.push({ params, strategyKey, errMsg });
}
start() {
for (const item of this.validateItems) {
const { params, strategyKey, errMsg } = item;
const msg = strategy[strategyKey](params, errMsg);
if (msg) {
return msg;
}
}
}
}
function validate() {
const username = document.getElementId('username');
const pwd = document.getElementId('pwd');
const mobile = document.getElementId('mobile');
const validator = new Validator();
validator.add({ value: username }, 'isEmpty', '用户名不可为空');
validator.add(
{ value: pwd, len: 6 },
'isLongerThanMinLength',
'密码长度不能少于6位'
);
validator.add({ value: mobile }, 'isMobile', '手机号码格式不正确');
const errMsg = validator.start();
if (errMsg) {
alert(errMsg);
} else {
alert('校验通过');
}
}
validate();
策略模式强调的是做同一件事的不同且不重复的方法 多态是一种语言机制,有的不支持多态的语言也一样要实现策略模式 策略处于程序设计层次,多态处于语言语法层次