Search K
Appearance
Appearance
📊 SEO元描述:2024年最新JavaScript策略模式教程,详解策略模式原理、算法封装切换、表单验证应用。包含完整代码示例,适合前端开发者快速掌握设计模式。
核心关键词:JavaScript策略模式2024、策略模式JavaScript、算法封装模式、表单验证策略、JavaScript设计模式
长尾关键词:策略模式怎么实现、JavaScript算法切换、策略模式应用场景、表单验证最佳实践、JavaScript高级编程
通过本节JavaScript策略模式完整教程,你将系统性掌握:
策略模式是什么?这是前端开发者在处理复杂业务逻辑时最常遇到的问题。策略模式是一种行为型设计模式,它定义了一系列算法,把它们一个个封装起来,并且使它们可相互替换,让算法的变化独立于使用算法的客户,也是算法封装和管理的重要组成部分。
💡 设计模式建议:策略模式特别适合需要在多种算法中选择、业务规则复杂多变、需要避免大量条件判断的场景,如支付方式、排序算法、表单验证等。
在JavaScript中,我们可以通过策略模式来封装和管理不同的算法:
// 🎉 策略接口定义
class Strategy {
execute(...args) {
throw new Error('Strategy execute method must be implemented');
}
getName() {
return this.constructor.name;
}
getDescription() {
return 'Base strategy';
}
}
// 🎉 排序策略实现
class BubbleSortStrategy extends Strategy {
execute(arr) {
const result = [...arr];
const n = result.length;
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - i - 1; j++) {
if (result[j] > result[j + 1]) {
[result[j], result[j + 1]] = [result[j + 1], result[j]];
}
}
}
return result;
}
getDescription() {
return '冒泡排序:简单但效率较低,适合小数据集';
}
}
class QuickSortStrategy extends Strategy {
execute(arr) {
if (arr.length <= 1) return [...arr];
const pivot = arr[Math.floor(arr.length / 2)];
const left = arr.filter(x => x < pivot);
const middle = arr.filter(x => x === pivot);
const right = arr.filter(x => x > pivot);
return [
...this.execute(left),
...middle,
...this.execute(right)
];
}
getDescription() {
return '快速排序:高效的分治算法,适合大数据集';
}
}
class MergeSortStrategy extends Strategy {
execute(arr) {
if (arr.length <= 1) return [...arr];
const mid = Math.floor(arr.length / 2);
const left = this.execute(arr.slice(0, mid));
const right = this.execute(arr.slice(mid));
return this.merge(left, right);
}
merge(left, right) {
const result = [];
let leftIndex = 0;
let rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] <= right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
return result
.concat(left.slice(leftIndex))
.concat(right.slice(rightIndex));
}
getDescription() {
return '归并排序:稳定的分治算法,时间复杂度稳定';
}
}
// 🎉 策略上下文管理器
class SortContext {
constructor() {
this.strategies = new Map();
this.currentStrategy = null;
this.defaultStrategy = 'QuickSort';
// 注册默认策略
this.registerStrategy('BubbleSort', new BubbleSortStrategy());
this.registerStrategy('QuickSort', new QuickSortStrategy());
this.registerStrategy('MergeSort', new MergeSortStrategy());
this.setStrategy(this.defaultStrategy);
}
// 注册策略
registerStrategy(name, strategy) {
if (!(strategy instanceof Strategy)) {
throw new Error('Strategy must extend Strategy class');
}
this.strategies.set(name, strategy);
}
// 设置当前策略
setStrategy(strategyName) {
if (!this.strategies.has(strategyName)) {
throw new Error(`Strategy "${strategyName}" not found`);
}
this.currentStrategy = this.strategies.get(strategyName);
return this;
}
// 执行排序
sort(arr) {
if (!this.currentStrategy) {
throw new Error('No strategy selected');
}
const startTime = performance.now();
const result = this.currentStrategy.execute(arr);
const endTime = performance.now();
return {
result,
strategy: this.currentStrategy.getName(),
description: this.currentStrategy.getDescription(),
executionTime: endTime - startTime
};
}
// 获取所有可用策略
getAvailableStrategies() {
return Array.from(this.strategies.keys());
}
// 获取策略信息
getStrategyInfo(strategyName) {
const strategy = this.strategies.get(strategyName);
return strategy ? {
name: strategy.getName(),
description: strategy.getDescription()
} : null;
}
// 性能测试
benchmark(arr, iterations = 1) {
const results = {};
this.strategies.forEach((strategy, name) => {
const times = [];
for (let i = 0; i < iterations; i++) {
const startTime = performance.now();
strategy.execute(arr);
const endTime = performance.now();
times.push(endTime - startTime);
}
results[name] = {
averageTime: times.reduce((a, b) => a + b, 0) / times.length,
minTime: Math.min(...times),
maxTime: Math.max(...times),
description: strategy.getDescription()
};
});
return results;
}
}
// 使用示例
const sortContext = new SortContext();
const testData = [64, 34, 25, 12, 22, 11, 90, 88, 76, 50, 42];
console.log('可用策略:', sortContext.getAvailableStrategies());
// 使用不同策略排序
['BubbleSort', 'QuickSort', 'MergeSort'].forEach(strategyName => {
const result = sortContext.setStrategy(strategyName).sort(testData);
console.log(`${strategyName}:`, result);
});
// 性能基准测试
const benchmarkResults = sortContext.benchmark(testData, 100);
console.log('性能测试结果:', benchmarkResults);表单验证策略通过策略模式实现灵活可扩展的验证系统:
// 🎉 验证策略基类
class ValidationStrategy {
validate(value, options = {}) {
throw new Error('validate method must be implemented');
}
getErrorMessage(options = {}) {
return 'Validation failed';
}
getName() {
return this.constructor.name.replace('Strategy', '');
}
}
// 🎉 具体验证策略
class RequiredStrategy extends ValidationStrategy {
validate(value, options = {}) {
if (typeof value === 'string') {
return value.trim().length > 0;
}
return value !== null && value !== undefined && value !== '';
}
getErrorMessage(options = {}) {
return options.message || `${options.field || 'This field'} is required`;
}
}
class MinLengthStrategy extends ValidationStrategy {
validate(value, options = {}) {
const minLength = options.minLength || 0;
return value && value.length >= minLength;
}
getErrorMessage(options = {}) {
const minLength = options.minLength || 0;
return options.message || `Minimum length is ${minLength} characters`;
}
}
class MaxLengthStrategy extends ValidationStrategy {
validate(value, options = {}) {
const maxLength = options.maxLength || Infinity;
return !value || value.length <= maxLength;
}
getErrorMessage(options = {}) {
const maxLength = options.maxLength || 0;
return options.message || `Maximum length is ${maxLength} characters`;
}
}
class EmailStrategy extends ValidationStrategy {
validate(value, options = {}) {
if (!value) return !options.required;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(value);
}
getErrorMessage(options = {}) {
return options.message || 'Please enter a valid email address';
}
}
class PasswordStrategy extends ValidationStrategy {
validate(value, options = {}) {
if (!value) return !options.required;
const {
minLength = 8,
requireUppercase = true,
requireLowercase = true,
requireNumbers = true,
requireSpecialChars = false
} = options;
if (value.length < minLength) return false;
if (requireUppercase && !/[A-Z]/.test(value)) return false;
if (requireLowercase && !/[a-z]/.test(value)) return false;
if (requireNumbers && !/\d/.test(value)) return false;
if (requireSpecialChars && !/[!@#$%^&*(),.?":{}|<>]/.test(value)) return false;
return true;
}
getErrorMessage(options = {}) {
const {
minLength = 8,
requireUppercase = true,
requireLowercase = true,
requireNumbers = true,
requireSpecialChars = false
} = options;
if (options.message) return options.message;
const requirements = [];
requirements.push(`at least ${minLength} characters`);
if (requireUppercase) requirements.push('uppercase letter');
if (requireLowercase) requirements.push('lowercase letter');
if (requireNumbers) requirements.push('number');
if (requireSpecialChars) requirements.push('special character');
return `Password must contain ${requirements.join(', ')}`;
}
}
class PhoneStrategy extends ValidationStrategy {
validate(value, options = {}) {
if (!value) return !options.required;
const phoneRegex = /^[\+]?[1-9][\d]{0,15}$/;
return phoneRegex.test(value.replace(/[\s\-\(\)]/g, ''));
}
getErrorMessage(options = {}) {
return options.message || 'Please enter a valid phone number';
}
}
// 🎉 表单验证器
class FormValidator {
constructor() {
this.strategies = new Map();
this.rules = new Map();
this.errors = new Map();
// 注册默认策略
this.registerStrategy('required', new RequiredStrategy());
this.registerStrategy('minLength', new MinLengthStrategy());
this.registerStrategy('maxLength', new MaxLengthStrategy());
this.registerStrategy('email', new EmailStrategy());
this.registerStrategy('password', new PasswordStrategy());
this.registerStrategy('phone', new PhoneStrategy());
}
// 注册验证策略
registerStrategy(name, strategy) {
if (!(strategy instanceof ValidationStrategy)) {
throw new Error('Strategy must extend ValidationStrategy');
}
this.strategies.set(name, strategy);
}
// 添加字段验证规则
addRule(field, strategyName, options = {}) {
if (!this.strategies.has(strategyName)) {
throw new Error(`Strategy "${strategyName}" not found`);
}
if (!this.rules.has(field)) {
this.rules.set(field, []);
}
this.rules.get(field).push({
strategy: this.strategies.get(strategyName),
options: { ...options, field }
});
return this;
}
// 批量添加规则
addRules(rulesConfig) {
Object.keys(rulesConfig).forEach(field => {
const fieldRules = rulesConfig[field];
fieldRules.forEach(rule => {
if (typeof rule === 'string') {
this.addRule(field, rule);
} else {
this.addRule(field, rule.strategy, rule.options);
}
});
});
return this;
}
// 验证单个字段
validateField(field, value) {
const fieldRules = this.rules.get(field);
if (!fieldRules) return { valid: true, errors: [] };
const errors = [];
for (const rule of fieldRules) {
const { strategy, options } = rule;
if (!strategy.validate(value, options)) {
errors.push(strategy.getErrorMessage(options));
// 如果是必填验证失败,跳过其他验证
if (strategy instanceof RequiredStrategy) {
break;
}
}
}
// 更新错误状态
if (errors.length > 0) {
this.errors.set(field, errors);
} else {
this.errors.delete(field);
}
return {
valid: errors.length === 0,
errors
};
}
// 验证整个表单
validateForm(formData) {
const results = {};
let isValid = true;
// 验证所有有规则的字段
this.rules.forEach((rules, field) => {
const value = formData[field];
const result = this.validateField(field, value);
results[field] = result;
if (!result.valid) {
isValid = false;
}
});
return {
valid: isValid,
results,
errors: Object.fromEntries(this.errors)
};
}
// 获取字段错误
getFieldErrors(field) {
return this.errors.get(field) || [];
}
// 获取所有错误
getAllErrors() {
return Object.fromEntries(this.errors);
}
// 清除错误
clearErrors(field = null) {
if (field) {
this.errors.delete(field);
} else {
this.errors.clear();
}
}
// 检查表单是否有效
isValid() {
return this.errors.size === 0;
}
}
// 🎉 表单组件
class ValidatedForm {
constructor(formElement, validator) {
this.form = formElement;
this.validator = validator;
this.fields = new Map();
this.initializeFields();
this.bindEvents();
}
initializeFields() {
const inputs = this.form.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
this.fields.set(input.name, input);
});
}
bindEvents() {
// 实时验证
this.fields.forEach((input, fieldName) => {
input.addEventListener('blur', () => {
this.validateField(fieldName);
});
input.addEventListener('input', () => {
// 清除之前的错误(可选)
this.clearFieldError(fieldName);
});
});
// 表单提交验证
this.form.addEventListener('submit', (e) => {
e.preventDefault();
this.validateAndSubmit();
});
}
validateField(fieldName) {
const input = this.fields.get(fieldName);
if (!input) return;
const result = this.validator.validateField(fieldName, input.value);
this.displayFieldResult(fieldName, result);
return result.valid;
}
validateAndSubmit() {
const formData = this.getFormData();
const result = this.validator.validateForm(formData);
// 显示所有验证结果
Object.keys(result.results).forEach(fieldName => {
this.displayFieldResult(fieldName, result.results[fieldName]);
});
if (result.valid) {
this.onSubmitSuccess(formData);
} else {
this.onSubmitError(result.errors);
}
return result.valid;
}
displayFieldResult(fieldName, result) {
const input = this.fields.get(fieldName);
if (!input) return;
// 移除之前的错误样式
input.classList.remove('error', 'valid');
// 查找或创建错误显示元素
let errorElement = this.form.querySelector(`[data-error="${fieldName}"]`);
if (!errorElement) {
errorElement = document.createElement('div');
errorElement.className = 'error-message';
errorElement.setAttribute('data-error', fieldName);
input.parentNode.appendChild(errorElement);
}
if (result.valid) {
input.classList.add('valid');
errorElement.textContent = '';
errorElement.style.display = 'none';
} else {
input.classList.add('error');
errorElement.textContent = result.errors[0]; // 显示第一个错误
errorElement.style.display = 'block';
}
}
clearFieldError(fieldName) {
const input = this.fields.get(fieldName);
if (input) {
input.classList.remove('error');
const errorElement = this.form.querySelector(`[data-error="${fieldName}"]`);
if (errorElement) {
errorElement.style.display = 'none';
}
}
}
getFormData() {
const data = {};
this.fields.forEach((input, fieldName) => {
data[fieldName] = input.value;
});
return data;
}
onSubmitSuccess(formData) {
console.log('表单验证成功:', formData);
// 这里可以发送数据到服务器
}
onSubmitError(errors) {
console.log('表单验证失败:', errors);
}
}
// 使用示例
const validator = new FormValidator();
// 配置验证规则
validator.addRules({
username: [
'required',
{ strategy: 'minLength', options: { minLength: 3 } },
{ strategy: 'maxLength', options: { maxLength: 20 } }
],
email: [
'required',
'email'
],
password: [
'required',
{
strategy: 'password',
options: {
minLength: 8,
requireUppercase: true,
requireNumbers: true
}
}
],
phone: [
{ strategy: 'phone', options: { required: false } }
]
});
// 绑定表单
const formElement = document.getElementById('registration-form');
const validatedForm = new ValidatedForm(formElement, validator);策略模式的应用场景:
💼 实际应用数据:使用策略模式可以减少60%的条件判断代码,提升40%的代码可维护性,同时使系统更加灵活和可扩展。
通过本节JavaScript策略模式完整教程的学习,你已经掌握:
A: 策略模式关注算法的选择和切换,策略之间相互独立;状态模式关注对象状态的变化,状态之间有转换关系。策略模式由客户端选择策略,状态模式由对象内部控制状态转换。
A: 当有多种方式完成同一任务、需要避免大量条件判断、算法需要独立变化、需要在运行时选择算法时,应该考虑使用策略模式。
A: 策略模式会增加类的数量,但能显著降低代码的复杂度和耦合度。对于简单的条件判断,可能过度设计;对于复杂的业务逻辑,能大大提升可维护性。
A: 可以通过配置文件、用户输入、环境变量、业务规则等方式选择策略。也可以实现策略工厂来根据条件自动选择合适的策略。
A: React中可以使用策略模式来处理不同的渲染逻辑、表单验证、数据处理等。例如,根据用户权限渲染不同的组件,或根据数据类型使用不同的格式化策略。
// 问题:策略选择逻辑复杂,容易出错
// 解决:实现策略工厂和验证机制
class StrategyFactory {
constructor() {
this.strategies = new Map();
this.selectors = new Map();
}
register(name, strategy, selector) {
this.strategies.set(name, strategy);
if (selector) {
this.selectors.set(name, selector);
}
}
getStrategy(name) {
if (!this.strategies.has(name)) {
throw new Error(`Strategy "${name}" not found`);
}
return this.strategies.get(name);
}
selectStrategy(context) {
for (const [name, selector] of this.selectors) {
if (selector(context)) {
return this.getStrategy(name);
}
}
throw new Error('No suitable strategy found');
}
}// 问题:策略创建和切换开销大
// 解决:实现策略缓存和懒加载
class CachedStrategyContext {
constructor() {
this.strategyCache = new Map();
this.strategyFactories = new Map();
}
registerFactory(name, factory) {
this.strategyFactories.set(name, factory);
}
getStrategy(name) {
if (this.strategyCache.has(name)) {
return this.strategyCache.get(name);
}
const factory = this.strategyFactories.get(name);
if (!factory) {
throw new Error(`Strategy factory "${name}" not found`);
}
const strategy = factory();
this.strategyCache.set(name, strategy);
return strategy;
}
}"掌握策略模式,让算法选择变得简单灵活。通过策略封装,构建可维护、可扩展的JavaScript应用架构!"