设计模式应用场景

前端常用设计模式及其实际应用场景

问题

前端开发中常用哪些设计模式?各自的应用场景是什么?

解答

1. 单例模式

确保一个类只有一个实例。适用于全局状态管理、弹窗、缓存等场景。

// 单例模式 - 全局弹窗管理
class Modal {
  static instance = null;

  static getInstance() {
    if (!Modal.instance) {
      Modal.instance = new Modal();
    }
    return Modal.instance;
  }

  show(content) {
    console.log('显示弹窗:', content);
  }

  hide() {
    console.log('隐藏弹窗');
  }
}

// 使用
const modal1 = Modal.getInstance();
const modal2 = Modal.getInstance();
console.log(modal1 === modal2); // true

2. 发布订阅模式

对象间一对多的依赖关系。适用于事件系统、组件通信、状态变化通知。

// 发布订阅 - 事件总线
class EventBus {
  constructor() {
    this.events = {};
  }

  // 订阅事件
  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  }

  // 发布事件
  emit(event, ...args) {
    const callbacks = this.events[event];
    if (callbacks) {
      callbacks.forEach(cb => cb(...args));
    }
  }

  // 取消订阅
  off(event, callback) {
    const callbacks = this.events[event];
    if (callbacks) {
      this.events[event] = callbacks.filter(cb => cb !== callback);
    }
  }
}

// 使用
const bus = new EventBus();
bus.on('login', user => console.log('用户登录:', user));
bus.emit('login', { name: '张三' }); // 用户登录: { name: '张三' }

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', ['required', 'minLength:6'])); // '最少6个字符'
console.log(validate('test@example.com', ['required', 'email'])); // true

4. 代理模式

为对象提供代理以控制访问。适用于懒加载、缓存、访问控制、Vue3 响应式。

// 代理模式 - 带缓存的请求
function createCachedFetch() {
  const cache = new Map();

  return new Proxy(fetch, {
    apply(target, thisArg, args) {
      const [url] = args;

      // 命中缓存直接返回
      if (cache.has(url)) {
        console.log('从缓存获取:', url);
        return Promise.resolve(cache.get(url));
      }

      // 发起请求并缓存
      return target.apply(thisArg, args)
        .then(res => res.json())
        .then(data => {
          cache.set(url, data);
          return data;
        });
    }
  });
}

const cachedFetch = createCachedFetch();

5. 装饰器模式

动态给对象添加额外职责。适用于日志记录、性能统计、权限校验、React HOC。

// 装饰器模式 - 函数增强
function withLogging(fn) {
  return function (...args) {
    console.log(`调用 ${fn.name},参数:`, args);
    const start = Date.now();
    const result = fn.apply(this, args);
    console.log(`执行耗时: ${Date.now() - start}ms`);
    return result;
  };
}

function withErrorHandler(fn) {
  return function (...args) {
    try {
      return fn.apply(this, args);
    } catch (e) {
      console.error('执行出错:', e.message);
      return null;
    }
  };
}

// 使用
function calculate(a, b) {
  return a + b;
}

const enhanced = withLogging(withErrorHandler(calculate));
enhanced(1, 2);
// 调用 calculate,参数: [1, 2]
// 执行耗时: 0ms

6. 工厂模式

封装对象创建过程。适用于根据条件创建不同类型对象。

// 工厂模式 - 创建不同类型的组件
class Button {
  render() {
    return '<button>按钮</button>';
  }
}

class Input {
  render() {
    return '<input type="text" />';
  }
}

class Select {
  render() {
    return '<select></select>';
  }
}

// 工厂函数
function createComponent(type) {
  const components = {
    button: Button,
    input: Input,
    select: Select
  };

  const Component = components[type];
  if (!Component) {
    throw new Error(`未知组件类型: ${type}`);
  }
  return new Component();
}

// 使用
const btn = createComponent('button');
console.log(btn.render()); // <button>按钮</button>

关键点

  • 单例模式:全局唯一实例,用于弹窗、Store、缓存
  • 发布订阅:解耦组件通信,Vue/React 事件系统的基础
  • 策略模式:消除 if-else,表单验证、价格计算常用
  • 代理模式:控制访问,Vue3 响应式、懒加载、缓存代理
  • 装饰器模式:不修改原函数增强功能,HOC、日志、权限
  • 工厂模式:封装创建逻辑,根据类型动态创建对象