定义:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
将不变的部分和变化的部分隔开是每个设计模式的主题,策略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来。
一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程;第二个部分是环境类 Context,Context 接受客户的请求,随后把请求委托给某一个策略类。
比如使用策略模式实现一个表单验证的功能:
先将策略名和要执行的策略方法列出来:
interface IValidateFunc {
(value: string, errorMessage: string, ...args: unknown[]): string | void;
}
// 策略名
const RULE_KEYS_MAP = {
isNotEmpty: "isNotEmpty",
isMobile: "isMobile",
minLength: "minLength",
};
// 要执行的策略方法
const validateIsNotEmpty: IValidateFunc = function (
value: string,
errorMessage: string
) {
if (!value) {
return errorMessage;
}
};
const validateIsMobile = function (
value: string,
errorMessage: string
): string | void {
if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
return errorMessage;
}
};
function validateMinLength(
value: string,
length: number | string,
errorMessage: string
): string | void {
console.log(value.length, length);
if (value.length < Number(length)) {
return errorMessage;
}
}
然后实现策略对象,将策略名作为对象的键,策略方法作为对象的值,实现映射:
const strategis: {
[key: string]: IValidateFunc;
} = Object.keys(RULE_KEYS_MAP).reduce((prev, key) => {
let func = null;
switch (key) {
case RULE_KEYS_MAP.isNotEmpty:
func = validateIsNotEmpty;
break;
case RULE_KEYS_MAP.isMobile:
func = validateIsMobile;
break;
case RULE_KEYS_MAP.minLength:
func = validateMinLength;
default:
break;
}
func && (prev[key] = func);
return prev;
}, {});
创建一个上下文类,用于管理和调用策略。
class Validator {
strategis: {
validateFunc: IValidateFunc;
value: string;
ruleParams: unknown[];
errorMessage: string;
}[];
constructor() {
this.strategis = [];
}
add(value: string, rule: string, errorMessage: string) {
const [ruleKey, ...ruleParams] = rule.split(":");
this.strategis.push({
validateFunc: strategis[ruleKey],
value,
ruleParams,
errorMessage,
});
}
run() {
this.strategis.forEach((strategy) => {
const { validateFunc, value, ruleParams, errorMessage } = strategy;
const message = validateFunc(value, errorMessage, ruleParams);
if (message) {
console.error(message);
}
});
}
}
实现了上面的功能后,下面模仿用户的使用,调用上下文类,配置策略,执行表单验证:
const validator = new Validator();
validator.add("13122224444", RULE_KEYS_MAP.isMobile, "电话号码格式不对");
validator.add("", RULE_KEYS_MAP.isNotEmpty, "这里不能为空");
validator.add("12345", `${RULE_KEYS_MAP.minLength}:6`, "最小长度要为6");
validator.run();
执行结果: