什么是装饰器模式

核心提示装饰器概念在开发过程中,很多时候我们不想要类的功能一开始就很庞大,一次性包含很多职责。这个时候我们可以使用装饰器模式。动态的给某个对象添加一些职责,并且不会影响从这个类派生的其他对象。在传统的面向对象开发中,给对象添加功能时,我们通常会采用

装饰装置概念

在开发过程中,很多时候我们并不希望类的功能一开始就很庞大,一次性包含很多职责。这时候我们可以使用装饰器模式。动态地给一个对象增加一些责任,不会影响从这个类派生的其他对象。

在传统的面向对象开发中,当向对象添加功能时,我们通常采用继承的方式。继承的目的是重用,但也带来了一些问题:

父类和子类之间有很强的耦合关系。当父类改变时,子类也需要改变。

子类需要知道父类的细节,至少是接口名,以便重用或复制,这实际上破坏了封装;

继承,可能会创建大量的子类。例如,现在有三种类型的BBA汽车,并且构建了一个汽车基类,三种类型的汽车。现在需要在汽车上安装雾灯、大灯、导航仪、雨刷。如果采用继承的方法,那么将构建3*4个类。但如果给汽车动态添加雾灯、大灯、导航仪、雨刷,那么只需要添加四个类。这种动态添加职责的方式就是装饰器。

装饰器的目的是在运行时向原始类动态添加职责,而不改变它。

用AOP修饰函数

为什么要在这里讨论AOP?这个问题我们以后再回答。

我们先来复习一下OOP。OOP作为一种面向对象的编程模型取得了巨大的成功,其主要思想是封装、继承和多态。

AOP是一种新的编程方法,不同于OOP。OOP将系统视为多个对象的交互,AOP将系统划分为不同的关注点,或部分。

AOP,意为面向对象编程,是一种通过预编译和动态代理实现程序功能时统一维护的技术。主要提取与业务逻辑无关的功能,如数据统计、功能执行时间、权限控制、异常处理等。这些功能提取出来后,通过动态切入注入到业务逻辑中。这有利于确保业务内部的高内聚和业务模块之间的低耦合,从而促进与业务逻辑无关的模块的重用。

这里为什么要结合decorator和AOP来讨论?

从上面的描述中,会发现AOP和decorator模式的概念类似,只是decorator注重的是装饰,而AOP注重的是断面的统一维护。其实两者最终都是为了解决同一个问题,就是提高编程的低耦合性和高复用性。

说了这么多,还是有点抽象。我们来看看实际的例子,如何在项目中应用AOP。

AOP的实现

AOP是Java Spring中最重要的功能之一。用过的同学一定知道,通知有三种,前,后,后。我们来模拟一下AOP中before和after的实现。

以前

顾名思义,它是在调用函数之前执行的。

function . prototype . before = function { var _ _ self = this;返回函数{ before fn . apply;return _ _ self.apply};};复制代码

在...之后

与之前相反,它在函数调用之后执行。

function . prototype . after = function { var _ _ self = this;返回函数{ var ret = _ _ self.applyafter fn . apply;返回ret};};复制代码

日志报告示例

接下来以数据报表为例,讲讲如何用AOP修饰函数。

例如,该页面有一个共享按钮。点击后会弹出一个分享框,与人分享。点击之后,需要上报数据。这一次,按照通常的方式,我们将这样实现它:

单击共享框复制代码。

你可以看到,在showShare函数中,它既负责打开弹出窗口,又负责报告统计数据。这是两个层次的内容,它们耦合在一起。经过AOP分离后,代码如下:

单击共享框复制代码。

数据提交功能在行数之后执行。当然,如果你想在函数之前执行,调用:

show share = show share . before;//打开共享框后上报数据复制代码。

可见不同职责的功能是严格分离的,避免耦合是AOP的目标,这也是decorator的作用。

再举个例子:ajax请求对于每个项目都是必不可少的,那么如何用AOP实现呢?

使用AOP解耦ajax参数

在项目中使用ajax请求,通常,我们可以封装一个统一的请求库,比如:

var ajax = function { console.dir//发送ajax请求的代码省略};ajax复制代码

Ajax功能在项目中一直运行良好,与后台的合作一直很愉快。直到有一天,我们的网站受到了CSRF的攻击。解决CSRF攻击的最好方法是在HTTP请求中添加一个令牌参数。现在的任务是为每个ajax函数添加一个令牌。这时,我们首先想到的是,我们需要修改ajax函数:

var Ajax = function { param = param | | { };参数。Token = getToken//发送ajax请求的代码略...};复制代码

虽然这个问题已经解决了,但是我们的ajax库已经变得不可重用,每个ajax请求都有一个令牌。虽然我的项目没有问题,但是如果要移植到其他项目或者开源,令牌就显得多余了。可能另一个项目不需要令牌,也可能令牌是以不同的方式生成的。

要解决这个问题,我们还是需要把ajax还原成一个纯粹的函数。

var ajax = function { console.log};复制代码

然后,用AOP的before修饰,并将token参数添加到param。

var getToken = function { return " Token ";};ajax = ajax.before { param。Token = getToken});ajax复制代码

可以看到,token参数是AOP动态添加到ajax中的,保持了ajax的请求函数的简单性,提高了ajax的可重用性。如果下次想在其他项目中使用,就不用做任何改动了。

AOP的实现

实际上,ES5语法用于模拟AOP的实现。在新一代JS语言中,已经实现了decorator的语法糖,Vscode的源代码甚至使用decorator来实现依赖注入模式。那么,AOP和decorator的结合是如何使用的呢?

日志报告示例

日志装饰器实现

导出函数日志{ var _ origin = decriptor.valuedescriptor . value = function { console . log;return _ origin.apply};返回描述符;}复制代码

调用装饰器

从“”导入{ log }。/log ";类人{ @ logsay { return `hi $ { nick }}}var person =新人;person.say复制代码

使用AOP解耦ajax参数

Ajax参数装饰器

函数getToken { return“token”;}//将token参数导出函数Decorate Token添加到Ajax { let method = descriptor . value;descriptor . value = function { args[2]。token = getToken方法.应用;};}复制代码

调用装饰器

class Util { @ decorateTokenstatic Ajax { console . log;} } Util.ajax复制代码

您可以看到参数被添加到ajax中:

摘要

Decorator模式在ES7和Typescript语法糖的支持下,越来越多的渗透到前端领域的开发中,JS也越来越庞大。以前只有Java或py中使用的AOP才能通过decorator模式应用到JS中。

通过对decorator的研究,我觉得挺有感触的。很多时候,我们会谈到某某设计模式,但是在代码中的应用其实很少。当工程逐渐庞大,耦合度越来越高,历史包袱越来越重,我们再走一步重建就更难了。

本文列举了日志提交和ajax请求的例子,并展示了decorator实际上是一种非常常见和不错的设计模式。有时候一个不起眼的功能,通过一点点“装饰”就会变得优雅纯粹。写出优雅的代码是一个程序员需要一直追求的目标和超越。

参考文章:

juejin.im/post/684490…

Javascript设计模式与开发实践

转自:file/tupian/20220910/p

 
友情链接
鄂ICP备19019357号-22