一、什么是策略模式?
策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用它的客户端。
简单来说,就是将不同的处理“策略”(算法)抽象出来,放到各自独立的类中。使用这些策略的“上下文”(Context)对象,可以在运行时根据需要,动态地选择并使用其中任何一个策略。
二、策略模式的核心组件
- 策略 (Strategy):通常是一个接口(
interface),它定义了所有支持的算法的公共操作。 - 具体策略 (Concrete Strategy):实现了策略接口的类,封装了具体的算法或行为。
- 上下文 (Context):持有一个策略对象的引用。它不直接执行任务,而是将任务委托给它所持有的策略对象来执行。上下文提供一个方法让客户端可以设置或更换策略。
三、示例:构建一个灵活的表单验证器
3.1 定义策略接口 (Strategy)
所有验证规则都必须遵循这个接口。
// Strategy: 验证策略的统一接口
interface IValidationStrategy {
validate(value: string): { isValid: boolean; message: string };
}
3.2 创建具体策略 (Concrete Strategies)
现在我们来实现几个具体的验证规则。
// Concrete Strategy 1: 非空验证
class RequiredStrategy implements IValidationStrategy {
validate(value: string) {
const isValid = value.trim() !== '';
return {
isValid,
message: isValid ? '' : '此字段为必填项。',
};
}
}
// Concrete Strategy 2: 邮箱格式验证
class EmailStrategy implements IValidationStrategy {
validate(value: string) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const isValid = emailRegex.test(value);
return {
isValid,
message: isValid ? '' : '请输入有效的邮箱地址。',
};
}
}
// Concrete Strategy 3: 最小长度验证
class MinLengthStrategy implements IValidationStrategy {
private minLength: number;
constructor(minLength: number) {
this.minLength = minLength;
}
validate(value: string) {
const isValid = value.length >= this.minLength;
return {
isValid,
message: isValid ? '' : `长度不能少于 ${this.minLength} 个字符。`,
};
}
}
3.3 创建上下文 (Context)
FormField 类就是我们的上下文。它持有一个验证策略,并用它来执行验证。
// Context: 使用验证策略的表单字段
class FormField {
private value: string;
private strategy: IValidationStrategy;
constructor(initialValue: string, strategy: IValidationStrategy) {
this.value = initialValue;
this.strategy = strategy;
}
// 允许在运行时更改验证策略
setValidationStrategy(strategy: IValidationStrategy) {
this.strategy = strategy;
}
setValue(value: string) {
this.value = value;
}
// 委托给策略对象执行验证
public validate() {
return this.strategy.validate(this.value);
}
}
3.4 将它们组合起来,感受动态切换的魅力
现在,我们可以轻松地创建和验证表单字段了。
// --- 客户端代码 ---
// 创建一个需要非空验证的用户名输入框
const usernameField = new FormField('', new RequiredStrategy());
console.log('用户名初始验证:', usernameField.validate()); // { isValid: false, message: '此字段为必填项。' }
usernameField.setValue('JohnDoe');
console.log('用户名输入后验证:', usernameField.validate()); // { isValid: true, message: '' }
console.log('\n' + '='.repeat(30) + '\n');
// 创建一个需要邮箱格式验证的邮箱输入框
const emailField = new FormField('not-an-email', new EmailStrategy());
console.log('邮箱格式错误验证:', emailField.validate()); // { isValid: false, message: '请输入有效的邮箱地址。' }
emailField.setValue('test@example.com');
console.log('邮箱格式正确验证:', emailField.validate()); // { isValid: true, message: '' }
console.log('\n' + '='.repeat(30) + '\n');
// 创建一个需要密码长度验证的密码输入框
const passwordField = new FormField('123', new MinLengthStrategy(8));
console.log('密码长度不足验证:', passwordField.validate()); // { isValid: false, message: '长度不能少于 8 个字符。' }
// 假设用户注册后,需要增加更强的密码策略,我们可以动态切换!
// passwordField.setValidationStrategy(new StrongPasswordStrategy()); // 假设我们新增了一个更复杂的策略
passwordField.setValue('password123');
console.log('密码长度足够验证:', passwordField.validate()); // { isValid: true, message: '' }
- 如果未来我们需要增加“手机号格式验证”或“身份证号验证”,只需创建一个新的策略类实现
IValidationStrategy接口即可,FormField类完全不需要任何改动。
为了方便大家学习和实践,本文的所有示例代码和完整项目结构都已整理上传至我的 GitHub 仓库。欢迎大家克隆、研究、提出 Issue,共同进步!
📂 核心代码与完整示例: GoF
总结
如果你喜欢本教程,记得点赞+收藏!关注我获取更多JavaScript/TypeScript开发干货