Skip to content

设计模式

要点速览

shell
创建型:管对象怎么造(单例、工厂)
结构型:管对象怎么组合(代理、装饰器)
行为型:管对象怎么通信(发布订阅、观察者、策略、迭代器)
优先掌握:单例、工厂、代理、发布订阅、装饰器 用的较多

常用模式案例

1、单例模式

一个类只能创建一个实例,全局共享,适用:全局弹窗、全局状态管理、日志工具

js

class Singleton {
  static instance = null;
  constructor() {
    this.data = "我是唯一实例";
  }
  // 获取唯一实例
  static getInstance() {
    if (!this.instance) this.instance = new Singleton();
    return this.instance;
  }
}

// 测试:两个变量指向同一个对象
const obj1 = Singleton.getInstance();
const obj2 = Singleton.getInstance();
console.log(obj1 === obj2); // true

2、工厂模式

不暴露创建逻辑,统一接口创建不同对象,适用:表单组件生成、不同类型弹窗、多类请求封装

js
// 工厂函数:根据类型创建对应对象
function createUser(type) {
  if (type === "admin") return { role: "管理员", permissions: ["增删改查"] };
  if (type === "user") return { role: "普通用户", permissions: ["查看"] };
}

const admin = createUser("admin");
const user = createUser("user");

3、代理模式

用代理对象控制原对象访问,做拦截 / 增强,适用:数据校验、缓存、懒加载、Vue3 响应式原理

js
// 代理:拦截对象属性读写
const user = { name: "张三", age: 20 };
const proxy = new Proxy(user, {
  get(target, key) {
    console.log(`读取了${key}`);
    return target[key];
  },
  set(target, key, value) {
    if (key === "age" && value < 0) throw new Error("年龄不能为负");
    target[key] = value;
  }
});

proxy.age = -5; // 报错:年龄不能为负

4、装饰器模式

不修改原代码,给对象动态添加功能,适用:日志埋点、权限校验、函数增强

js
// 原函数
function sayHi() { console.log("你好"); }
// 装饰器:添加日志
function logDecorator(fn) {
  return function() {
    console.log("执行前日志");
    fn();
    console.log("执行后日志");
  };
}

const sayHiWithLog = logDecorator(sayHi);
sayHiWithLog(); // 日志 + 原功能

5、观察者模式

一个对象变化,自动通知所有依赖对象,适用:事件监听、状态更新、消息通知

js
class Subject {
  observers = [];
  // 添加观察者
  add(ob) { this.observers.push(ob); }
  // 通知所有观察者
  notify() { this.observers.forEach(ob => ob.update()); }
}

// 观察者
const observer = { update: () => console.log("收到通知!") };

const sub = new Subject();
sub.add(observer);
sub.notify(); // 自动触发

6、发布 - 订阅模式

比观察者更解耦,通过事件中心通信,适用:Vue 事件总线、跨组件通信

js
// 简易事件总线
class EventBus {
  events = {};
  on(type, fn) { this.events[type] = this.events[type] || []; this.events[type].push(fn); }
  emit(type, ...args) { this.events[type]?.forEach(fn => fn(...args)); }
}

const bus = new EventBus();
bus.on("login", (user) => console.log(user + "登录成功"));
bus.emit("login", "张三");

7、策略模式

把不同算法封装成策略,灵活切换,适用:表单校验、支付方式切换、权限判断

js
// 策略:不同校验规则
const strategies = {
  required: (val) => val !== "",
  minLength: (val, len) => val.length >= len
};

// 校验函数
function validate(val, rule) {
  return strategies[rule](val, 6);
}

console.log(validate("12345", "minLength")); // false

8、迭代器模式

统一遍历不同数据结构,适用:遍历数组 / 对象 / 树结构、自定义遍历逻辑

js
// 简易迭代器
function iterator(data) {
  let index = 0;
  return { next: () => ({ value: data[index++], done: index > data.length }) };
}

const it = iterator([1,2,3]);
console.log(it.next()); // { value:1, done:false }