设计模式应用

前端开发中常用的设计模式及实际应用场景

问题

前端开发中用过哪些设计模式?请举例说明。

解答

1. 单例模式

确保一个类只有一个实例,常用于全局状态管理。

// 单例模式 - 全局状态管理
class Store {
  static instance = null;
  
  constructor() {
    if (Store.instance) {
      return Store.instance;
    }
    this.state = {};
    Store.instance = this;
  }
  
  setState(key, value) {
    this.state[key] = value;
  }
  
  getState(key) {
    return this.state[key];
  }
}

// 使用
const store1 = new Store();
const store2 = new Store();
console.log(store1 === store2); // true

2. 发布订阅模式

解耦事件的发布者和订阅者,常用于组件通信。

// 发布订阅模式 - EventEmitter
class EventEmitter {
  constructor() {
    this.events = {};
  }
  
  // 订阅事件
  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
    return this;
  }
  
  // 发布事件
  emit(event, ...args) {
    const callbacks = this.events[event];
    if (callbacks) {
      callbacks.forEach(cb => cb(...args));
    }
    return this;
  }
  
  // 取消订阅
  off(event, callback) {
    if (this.events[event]) {
      this.events[event] = this.events[event].filter(cb => cb !== callback);
    }
    return this;
  }
}

// 使用
const emitter = new EventEmitter();
emitter.on('login', user => console.log(`${user} 登录了`));
emitter.emit('login', '张三'); // 张三 登录了

3. 策略模式

定义一系列算法,使它们可以互相替换,常用于表单验证、价格计算。

// 策略模式 - 表单验证
const validators = {
  required: value => value !== '' || '必填项',
  email: value => /^[\w-]+@[\w-]+\.\w+$/.test(value) || '邮箱格式错误',
  minLength: (value, len) => value.length >= len || `最少${len}个字符`,
  phone: value => /^1\d{10}$/.test(value) || '手机号格式错误'
};

// 验证函数
function validate(value, rules) {
  for (const rule of rules) {
    const [name, ...args] = rule.split(':');
    const result = validators[name](value, ...args);
    if (result !== true) {
      return result; // 返回错误信息
    }
  }
  return true;
}

// 使用
console.log(validate('', ['required'])); // 必填项
console.log(validate('abc', ['email'])); // 邮箱格式错误
console.log(validate('test@qq.com', ['required', 'email'])); // true

4. 代理模式

控制对对象的访问,常用于数据劫持、缓存代理。

// 代理模式 - 响应式数据
function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      console.log(`读取 ${key}`);
      return target[key];
    },
    set(target, key, value) {
      console.log(`设置 ${key} = ${value}`);
      target[key] = value;
      // 触发视图更新...
      return true;
    }
  });
}

// 使用
const state = reactive({ count: 0 });
state.count; // 读取 count
state.count = 1; // 设置 count = 1

5. 装饰器模式

动态给对象添加功能,不改变原有结构。

// 装饰器模式 - 函数增强
function withLogging(fn) {
  return function(...args) {
    console.log(`调用 ${fn.name},参数:`, args);
    const result = fn.apply(this, args);
    console.log(`返回:`, result);
    return result;
  };
}

function add(a, b) {
  return a + b;
}

// 使用
const loggedAdd = withLogging(add);
loggedAdd(1, 2);
// 调用 add,参数: [1, 2]
// 返回: 3

6. 工厂模式

封装对象创建过程,常用于组件创建。

// 工厂模式 - 创建弹窗组件
function createModal(type, options) {
  const modals = {
    alert: { icon: '⚠️', buttons: ['确定'] },
    confirm: { icon: '❓', buttons: ['取消', '确定'] },
    success: { icon: '✅', buttons: ['确定'] }
  };
  
  return {
    ...modals[type],
    ...options,
    show() {
      console.log(`${this.icon} ${this.message}`);
    }
  };
}

// 使用
const modal = createModal('confirm', { message: '确定删除吗?' });
modal.show(); // ❓ 确定删除吗?

关键点

  • 单例模式:全局唯一实例,适用于 Store、缓存、配置管理
  • 发布订阅:解耦组件通信,Vue/React 事件系统的基础
  • 策略模式:消除 if-else,让算法可配置、可扩展
  • 代理模式:Vue3 响应式原理,实现数据劫持和访问控制
  • 装饰器模式:HOC、函数增强,不修改原代码添加功能
  • 工厂模式:封装创建逻辑,统一管理对象实例化