「软件设计模式杂谈🤔」如何调一杯“程序咖啡”?看看装饰器模式

187 阅读2分钟

Hi!这里是 JustHappy,咱前端写多了组件、搞多了逻辑,是不是总会遇到某些功能“忍不住想加一嘴”?又不想动原来的代码?那你就该认识一下——装饰器模式(Decorator Pattern) 啦!

image.png

装饰器模式是啥?🎁

来!我们还得看看百科怎么说!(以下引用自维基百科)

设计模式中,装饰器模式(Decorator Pattern)允许向一个现有对象添加新的功能,同时又不改变其结构。这个模式创建了一个装饰类,用来包裹原有的类,并在保持原有类方法签名完整性的前提下,提供额外的行为。

一句话总结:你不动原来的代码,就能加功能!是不是很香?

image.png

来个生活化比喻 🎩

你买了杯咖啡(原始对象),但你突然想加点奶加点糖甚至来点抹茶?你不会去工厂改配方,而是……一层一层往上加!

☕ 咖啡 + 奶 → 奶咖
☕ 咖啡 + 糖 → 甜咖
☕ 咖啡 + 奶 + 糖 + 抹茶 → 精致贵妇快乐水

这就是装饰器模式的精髓!

🌈 试想一个场景!

比如你写了一个 log() 函数,控制台输出日志:

    function log(message) {
      console.log(message)
    }

某一天你领导说:“能不能加个时间戳?”

你加了:

    function log(message) {
      console.log(`[${new Date().toISOString()}] ${message}`)
    }

又过了两天:“能不能加个颜色?”

你又加了:

    function log(message) {
      console.log(`%c[${new Date().toISOString()}] ${message}`, 'color: green')
    }

再后来……你疯了……

🧠 冷静下来,来点“装饰器模式”!

我们不改原来的 log() 函数,而是“装饰”它!

// 基础 log 函数,支持样式参数
function log(message, style = '') {
  console.log(`%c${message}`, style)
}

// 装饰器1:加时间戳
function withTimestamp(fn) {
  return function(message, style) {
    const timestamp = `[${new Date().toISOString()}]`
    fn(`${timestamp} ${message}`, style)
  }
}

// 装饰器2:大写输出
function withUpperCase(fn) {
  return function(message, style) {
    fn(message.toUpperCase(), style)
  }
}

// 装饰器3:加颜色样式
function withColor(fn, color = 'green') {
  return function(message, style = '') {
    const combinedStyle = `color: ${color}; ${style}`
    fn(message, combinedStyle)
  }
}

// 装饰器组合(从里到外,顺序很重要)
let enhancedLog = withColor(
  withUpperCase(
    withTimestamp(log)
  ),
  'blue'
)

// 使用
enhancedLog('Hello, Decorator!')

👀 输出效果:

image.png

🧬 装饰器模式的几个关键词!

🔧 特性✅ 说明
开闭原则对扩展开放,对修改封闭!
灵活组合想怎么装就怎么装,叠叠乐~
保持原接口不改原有代码,老代码继续跑
类 or 函数都能用JS世界里都能玩得转

💡 在前端项目里怎么玩?

  • 日志增强:如上面那样包装 console.log
  • 组件增强:高阶组件(HOC)其实就是 React 里的装饰器!
  • 请求包装:封装 fetch,自动加 token、加 loading、加缓存
  • 表单校验:字段装饰,校验逻辑统一注入

📝 最后总结一下!

装饰器模式,就像给已有能力 “加特效”

  • 你不破坏原功能 ✅
  • 你可以层层叠加 ✅
  • 最终效果华丽又不乱 ✅