定义:
装饰器模式(Decorator Pattern)是一种结构型设计模式,用于在不改变原有对象的基础上,动态地给对象添加功能或职责。它通过在运行时包装对象来增加新的行为,从而提供了一种灵活的方式来扩展对象的功能。
装饰器模式包括两种主要角色:被装饰者(Component)和装饰者(Decorator)。被装饰者是一个接口或抽象类,定义了可以添加装饰的对象的接口。装饰者则实现了与被装饰者相同的接口,并持有一个指向被装饰者的引用。装饰者可以在其方法中调用被装饰者的方法,从而在被装饰者的行为之前或之后添加新的行为。
装饰器模式的优点包括:
- 动态扩展:可以在运行时动态地为对象添加功能,而无需修改其类定义。
- 灵活性:可以根据需要组合多个装饰器来创建具有不同行为的对象。
- 透明性:对于使用装饰器模式的客户端来说,被装饰者和装饰者对象都是一致的,因此它们可以无缝地替换彼此。
装饰器模式在多种场景下都非常有用,例如:
- 当需要动态地为一个对象添加功能时,可以使用装饰器模式来扩展其功能。
- 当需要以不同的方式组合对象的功能时,装饰器模式可以提供灵活的解决方案。
- 当需要对对象进行透明的包装以提供额外的功能或修改其行为时,可以使用装饰器模式
1.JS中如何动态的为一个对象添加功能
1.1定义函数前置方法和后置方法
前置:
这里可以看到,我在Function构造函数上添加了一个原型方法,名字叫before,当我想为我现在的函数或者某个对象添加功能的时候,就传入一个beforeFn,这个函数是我想向对象添加功能,并且在原函数执行之前执行的函数,var _this = this,这里是要保证我们函数this的指向和原函数要保持一致,举个例子:
在这个图片里面,ceshi函数this原本是指向window的,当我给他绑定到inp上的时候,function谁调用指向那个对象,此时ceshi输出的this就是input这个dom元素,同理,假如我有一个按钮,正常这个按钮的功能是当我点击他的时候,进行一个页面的跳转,但是现在我想给这个按钮加一个功能,就是让它跳转前,去上传一些数据。此时很多人都会在button这个按钮绑定的事件函数中去添加代码去实现这个效果,但是如果一个项目中有20,30或者更多的按钮需要加这个功能呢,一个一个添加的话,增加代码并且可读性变差,此时,我们就可以用装饰器模式,为这个按钮所绑定的函数加一个功能。
DOM:
js:
初学者看这里可能已经有点懵了,但是细细研读我写的解释,其实还是很好理解的,首先我没获取dom,是因为id可以作为dom去直接使用onclik绑定事件,接着,原先我的按钮,当我点击的时候,它只会执行render()这个函数,这个函数的功能是做一些页面处理逻辑,例如跳转页面,但是我现在有一个新的需求,想在跳转页面前执行一个log函数,这个函数的功能是提交一些数据,此时我就写了render = render.before(log),我们来读一下,点击按钮时触发render()函数,原本只会输出页面处理逻辑,但是在执行之前我给render做了一个重新赋值,让它等于render.before(log),此时我们就调用了Function这个原型的before方法,接着render.before(log)其实就等价于
beforeFn,就是我们的log方法,本来log方法的指向时windows,现在通过apply改变了log方法的指向,让它指向了button,同时还执行了log函数,如果这里不理解的可以去看看call,bind,apply的区别:
call、bind和apply之间的主要区别体现在以下三个方面:
- 执行方式:
- call和apply是改变后页面加载之后就立即执行,是同步代码。
- bind是异步代码,改变后不会立即执行,而是返回一个新的函数。
- 传参方式:
- call和bind可以接受多个参数,除了一个是this指向外,其余的参数对应函数的参数。
- apply只接受两个参数,第一个参数是this的指向,第二个参数是一个数组或者类数组对象,其中的数组元素将作为单独的参数传给函数。
- 修改this的性质:
- call和apply直接修改了函数的this上下文。
- bind返回一个新的函数,这个函数的this被永久地绑定到了bind的第一个参数。如果这个新函数作为构造函数被调用,那么this不再指向传入bind()的第一个参数,而是指向新生成的对象。
在JavaScript中,这些函数方法常常用于控制函数执行时的上下文(即this的值),使得函数可以按照我们期望的方式操作特定的对象。它们都是Function.prototype上的方法,因此所有的函数都可以使用它们。
所以在这里,我们的log函数就已经执行了,并且最后return了_this.apply(this.arguments),_this=this前面我们就已经把它缓存起来了,_this指向的是原来的函数,也就是原来的render
而现在的this,就变成了windows对象了,因为是在windows对象里用的function,return _this.apply(this.arguments),这里其实做了两步,第一步,首先把原函数给执行了,并且把原函数的this,指向了window。第二步返回原函数的返回值,这里我们是没有返回值的,如果说在原来的render函数中加上return 11111,然后在最后调用的时候输出console.log(render()),就能拿到11111
所以整体执行顺序为,在点击之前,我们使用装饰器模式给render添加了新功能,log,当我们点击按钮的时候,其实触发的函数,就是新的render.
同理,如果要在原来的render函数后面加功能,可以这么写:
总结:js的基础很重要,不然的话接触设计模式,确实很难懂,先把基础看会了,再来接触设计模式,能得到更好的效果,以上就是js设计模式之装饰器模式的用法和案例。