设计模式
要点速览
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); // true2、工厂模式
不暴露创建逻辑,统一接口创建不同对象,适用:表单组件生成、不同类型弹窗、多类请求封装
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")); // false8、迭代器模式
统一遍历不同数据结构,适用:遍历数组 / 对象 / 树结构、自定义遍历逻辑
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 }