关于装饰器模式我所知道的

简介: 关于装饰器模式我所知道的

image.png


持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

关键词:结构型模式 Decorator Wrapper 动态增加功能 原型高达挂载武器模块

在设计上更像是 AOP 的设计思路。也可以理解成 react 中的 HOC。


解决什么问题?


装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。

它主要的作用是给原始类添加增强功能。用于一开始不能确定对象的全部功能时,为对象动态加入行为,也可以说是增强功能。

相对于继承,有两个特殊的地方:

  1. 装饰器和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类。
  2. 装饰器是对功能的增强,这也是装饰器模式应用场景的一个重要特点。

举个例子:

继承的加强类似假两件,装饰器的加强类似单品穿搭。

class Body {
  wear() {
    console.log('Body!')
  }
}
class TshirtDecorator {
  constructor(body) {
    this.body = body
  }
  wear() {
    this.body.wear();
    console.log('穿T恤')
  }
}
class JacketDecorator {
  constructor(body) {
    this.body = body
  }
  wear() {
    this.body.wear()
    console.log('穿夹克')
  }
}
let p = new Body();
p = new TshirtDecorator(p)
p = new JacketDecorator(p)
p.wear()
// Body!
// 穿T恤
// 穿夹克


应用场景


不希望某个类天生就非常庞大,一次性包含许多职责。那么我们就可以使用装饰者模式。

侧重于功能,或者拆分方法的时候,推荐使用装饰器模式。并且可以嵌套多个装饰器类。


具体实践


原始代码

image.png


修改为一个简单的 HOC 组件

image.png


外面再嵌套一个装饰器


image.png

工具函数一览


const before = (fn, beforefn) => {
  return function () {
    beforefn.apply(this, arguments)
    return fn.apply(this,arguments)
  }
}
const after = (fn, afterfn) => {
  return function () {
    const res = fn.apply(this,arguments)
    afterfn.apply(this, arguments)
    return res
  }
}
let bf = before(function () { alert(3) }, function () { alert(2) })
bf = before(bf, function () { alert(1) })
bf()
let af = after(function () { alert(3) }, function () { alert(2) })
af = after(af, function () { alert(1) })
af()

数据统计上报

// html
<button id="btn" tag="login">点击打开登录框</button>
const log = (tag) => {
  console.log(`上报标签为${tag}`)
}
function showLogin() {
  console.log('打开弹窗', this)
  log(this.getAttribute('tag'))
}
// 页面登录按钮,点击弹出登录框,并进行数据上报
document.getElementById('btn').addEventListener('click', showLogin)

解耦数据上报和登录弹窗两项功能。

const after = (fn, afterfn) => {
  return function () {
    const res = fn.apply(this, arguments)
    afterfn.apply(this, arguments)
    return res
  }
}
function showLogin() {
  console.log('打开弹窗')
}
function log() {
  console.log(`上报标签为${this.getAttribute('tag')}`)
}
showLogin = after(showLogin, log)
document.getElementById('btn').addEventListener('click', showLogin)


动态修改函数参数

const before = (fn, beforefn) => {
  return function () {
    beforefn.apply(this, arguments)
    return fn.apply(this, arguments)
  }
}
const getToken = () => 'token'
function ajax(type, url, params) {
  console.table(params)
}
// 给请求添加token
ajax = before(ajax, function (type, url, params) {
  params.token = getToken()
})
ajax('get', 'url', { name: 'kane' })


插件式表单验证


// html
// 用户名 <input type="text" id="name"/>
// 密码 <input type="password" id="pwd"/>
// <button id="btn" tag="login">提交</button>
const name = document.getElementById('name');
const pwd = document.getElementById('pwd');
const btn = document.getElementById('btn');
Function.prototype.before = function (beforefn) {
  const _this = this;
  return function () {
    if (beforefn.apply(this, arguments) === false) return;
    return _this.apply(this, arguments)
  }
}
const validata = () => {
  if (name.value === '' || pwd.value === '') {
    alert(`不能为空`)
    return false
  }
  return true
}
let submit = () => {
  const params = {
    name: name.value,
    pwd: pwd.value,
  }
  // 提交数据
  console.log(params)
}
submit = submit.before(validata)
btn.onclick = () => {
  submit()
}


参考资料

hoc pattern

refactoringguru decorator

目录
相关文章
|
7月前
结构型 装饰器模式
结构型 装饰器模式
34 0
|
5月前
|
设计模式
对于装饰器模式与代理模式的个人理解
摘要: 代理模式与装饰器模式虽相似,但目的不同。装饰器动态增强对象功能,如添加新特性,而不改变原有类。代理模式则用于控制访问,如优化昂贵操作或添加辅助服务(如日志),它可能在内部初始化原对象。用法上,装饰器由外部决定是否应用,允许链式创建,而代理通常内部调用,外部直接与代理交互,被代理对象可能独立不可用。
|
7月前
|
设计模式
装饰器模式
装饰器模式
36 0
|
7月前
|
设计模式 C++
【C++】—— 装饰器模式
【C++】—— 装饰器模式
|
设计模式
2023-6-26-第八式装饰器模式
2023-6-26-第八式装饰器模式
78 0
装饰者模式
装饰者模式
75 0
打扮一下(装饰模式)
打扮一下(装饰模式)
66 0
|
设计模式
我认为的装饰器模式
我认为的装饰器模式
101 0