设计模式文档

设计模式不是八股文,而是前人总结的解决常见问题的最优方案。这篇文章用 JavaScript 实现最常用的设计模式,配代码示例和适用场景。

一、五大设计原则(SOLID)

原则 含义
单一职责(SRP) 一个类只做一件事
开放封闭(OCP) 对扩展开放,对修改封闭
里氏替换(LSP) 子类必须能替换父类
接口分离(ISP) 不依赖不需要的接口
依赖倒置(DIP) 依赖抽象,不依赖具体实现

二、工厂模式

通过参数决定创建哪个对象,不用直接 new。

class User {
  constructor(name) { this.name = name; }
  sayHi() { console.log(`Hi, ${this.name}`); }
}

class Admin {
  constructor(name) { this.name = name; }
  deleteUser(id) { console.log(`${this.name} deleted user ${id}`); }
}

function createUser(type, name) {
  if (type === 'admin') return new Admin(name);
  return new User(name);
}

const admin = createUser('admin', 'Tom');
admin.deleteUser(1);

适用场景:根据配置或用户选择创建不同类型的对象,如弹窗、按钮、支付方式。

三、单例模式

确保一个类只有一个实例。

class Config {
  static instance;
  constructor() {
    if (Config.instance) return Config.instance;
    this.apiUrl = '/api';
    Config.instance = this;
  }
}

const c1 = new Config();
const c2 = new Config();
console.log(c1 === c2); // true

适用场景:全局配置、数据库连接池、全局状态管理。

四、观察者模式

一对多依赖,状态变化时自动通知所有观察者。

class Subject {
  constructor() { this.observers = []; }
  subscribe(fn) { this.observers.push(fn); }
  notify(data) { this.observers.forEach(fn => fn(data)); }
}

const topic = new Subject();
topic.subscribe(data => console.log('订阅者1:', data));
topic.subscribe(data => console.log('订阅者2:', data));
topic.notify('新消息!');

实际应用:Vue 的响应式系统、DOM 事件监听、Redux 的 subscribe。

五、代理模式

不直接访问目标对象,通过代理控制访问。

const api = {
  getUser: (id) => fetch(`/api/users/${id}`).then(r => r.json())
};

// 缓存代理
const apiProxy = new Proxy(api, {
  cache: {},
  get(target, prop) {
    return async (id) => {
      if (this.cache[prop + id]) return this.cache[prop + id];
      const result = await target[prop](id);
      this.cache[prop + id] = result;
      return result;
    };
  }
});

适用场景:缓存、权限校验、日志记录、防抖节流。

六、策略模式

把可互换的算法封装成策略,运行时切换。

const strategies = {
  normal: price => price,
  vip: price => price * 0.8,
  holiday: price => price * 0.5
};

function calculatePrice(price, type) {
  return strategies[type](price);
}

console.log(calculatePrice(100, 'vip')); // 80
console.log(calculatePrice(100, 'holiday')); // 50

适用场景:多种折扣计算、表单验证规则、排序算法切换。

七、装饰器模式

不修改原对象,动态添加功能。

function withLogging(fn) {
  return function(...args) {
    console.log(`调用 ${fn.name},参数:`, args);
    const result = fn.apply(this, args);
    console.log(`返回值:`, result);
    return result;
  };
}

const add = (a, b) => a + b;
const loggedAdd = withLogging(add);
loggedAdd(1, 2);

实际应用:TypeScript 装饰器、React HOC(高阶组件)。

八、适配器模式

把不兼容的接口转换成可用的接口。

// 旧系统返回的数据格式
const oldSystem = { getData: () => ({ user_name: 'Tom', user_age: 20 }) };

// 新系统需要的格式
function displayUser({ name, age }) {
  console.log(`${name}, ${age}岁`);
}

// 适配器
function adaptOldData(data) {
  return { name: data.user_name, age: data.user_age };
}

displayUser(adaptOldData(oldSystem.getData()));

适用场景:对接第三方 API、迁移旧系统、兼容不同数据格式。

九、状态模式

对象状态改变时改变行为,避免大量 if/else。

class Order {
  constructor() { this.state = 'pending'; }
  next() {
    if (this.state === 'pending') this.state = 'paid';
    else if (this.state === 'paid') this.state = 'shipped';
    else if (this.state === 'shipped') this.state = 'completed';
    console.log('当前状态:', this.state);
  }
}

适用场景:订单流转、播放器状态(播放/暂停/停止)、表单状态。

十、迭代器模式

统一遍历不同数据结构的方式。

// ES6 原生迭代器协议
const arr = [1, 2, 3];
const map = new Map([['a', 1]]);

for (const item of arr) console.log(item);
for (const [key, value] of map) console.log(key, value);

适用场景:遍历数组、Set、Map、自定义集合。

总结

模式 一句话记忆
工厂 根据参数创建对象
单例 全局唯一实例
观察者 状态变化自动通知
代理 控制访问,加缓存/日志
策略 算法可互换
装饰器 动态加功能不改原代码
适配器 接口转换
状态 状态驱动行为
迭代器 统一遍历接口

相关阅读

posted @ 2026-10-14 01:32  博雅塔之子  阅读(2)  评论(0)    收藏  举报