设计模式分类
- 创建型:单例、工厂、原型
- 结构型:代理、装饰器、适配器
- 行为型:观察者、策略、状态
一、单例模式
核心思想
保证一个类只有一个实例,并提供全局访问点
// 懒汉式单例
class Singleton {
constructor() {
if (Singleton.instance) {
return Singleton.instance
}
Singleton.instance = this
}
}
// 函数式单例
function createSingleton(name) {
let instance = null
return function () {
if (!instance) {
instance = { name }
}
return instance
}
}
// 使用场景
// - Vuex/Pinia store
// - 全局配置对象
// - 日志对象二、工厂模式
核心思想
将对象的创建与使用分离
// 简单工厂
class Animal {
constructor(name) {
this.name = name
}
}
function createAnimal(type, name) {
if (type === "dog") return new Dog(name)
if (type === "cat") return new Cat(name)
return new Animal(name)
}
// 工厂方法
class DogFactory {
create(name) {
return new Dog(name)
}
}
// 使用场景
// - Vue 组件创建
// - 批量创建相似对象三、原型模式
核心思想
通过克隆现有对象来创建新对象
// 原型链继承
const proto = {
sayHello() {
console.log("Hello")
},
}
const obj1 = Object.create(proto)
const obj2 = Object.create(proto)
// 使用场景
// - 对象创建成本高
// - 需要保留原型的某些特性四、观察者模式(发布订阅)
核心思想
定义对象间的一对多依赖,当一个对象改变时,所有依赖者都会收到通知
// 实现一个简单的 EventBus
class EventEmitter {
constructor() {
this.events = {}
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = []
}
this.events[event].push(callback)
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach((cb) => cb(data))
}
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter((cb) => cb !== callback)
}
}
}
// 使用场景
// - Vue 的 $emit/$on
// - Node.js EventEmitter
// - 组件间通信五、策略模式
核心思想
定义一系列算法,把它们封装起来,使它们可以互相替换
// 传统写法
function calculatePrice(price, type) {
if (type === "normal") return price
if (type === "sale") return price * 0.8
if (type === "half") return price * 0.5
}
// 策略模式
const strategies = {
normal: (price) => price,
sale: (price) => price * 0.8,
half: (price) => price * 0.5,
}
function calculatePrice(price, type) {
return strategies[type](price)
}
// 使用场景
// - 表单验证
// - 价格计算
// - 排序算法六、代理模式
核心思想
为其他对象提供一种代理以控制对这个对象的访问
// 缓存代理
function createProxy(fn) {
const cache = {}
return function (...args) {
const key = JSON.stringify(args)
if (cache[key]) {
console.log("命中缓存")
return cache[key]
}
const result = fn(...args)
cache[key] = result
return result
}
}
// Vue3 响应式代理
const obj = new Proxy(
{ name: "张三" },
{
get(target, key) {
console.log(`访问 ${key}`)
return target[key]
},
set(target, key, value) {
console.log(`设置 ${key} = ${value}`)
target[key] = value
return true
},
},
)
// 使用场景
// - 缓存代理
// - 虚拟代理(图片懒加载)
// - 安全代理
// - Vue3 响应式七、装饰器模式
核心思想
在不改变原对象的情况下,动态地给对象添加新功能
// 类装饰器
function readonly(target, key, descriptor) {
descriptor.writable = false
return descriptor
}
// 函数装饰器
function log(target, name, descriptor) {
const original = descriptor.value
descriptor.value = function (...args) {
console.log(`Calling ${name} with`, args)
return original.apply(this, args)
}
return descriptor
}
// 使用场景
// - React 高阶组件
// - 日志记录
// - 权限控制八、适配器模式
核心思想
将一个类的接口转换成客户希望的另一个接口
// 电源适配器
class ChinaSocket {
charge() {
return "中国标准充电"
}
}
class USAdapter {
constructor() {
this.socket = new ChinaSocket()
}
charge() {
return this.socket.charge() // 转换接口
}
}
// 使用场景
// - 接口兼容
// - 数据格式转换
// - Vue 组件封装九、模式对比
| 模式 | 目的 | 特点 |
|---|---|---|
| 单例 | 保证唯一实例 | 全局唯一 |
| 工厂 | 解耦创建与使用 | 灵活创建 |
| 观察者 | 一对多通知 | 松耦合 |
| 策略 | 算法可替换 | 消除条件判断 |
| 代理 | 控制访问 | 增加中间层 |
| 装饰器 | 动态添加功能 | 不修改原对象 |
| 适配器 | 接口转换 | 兼容性处理 |