前端解读面向切面编程(AOP)

前言

面向对象(OOP)作为经典的设计范式,对于我们来说可谓无人不知,还记得我们入行起始时那句经典的总结吗-万事万物皆对象
是的,基于OOP思想封装、继承、多态的特点,我们会自然而然的遵循模块化、组件化的思维来设计开发应用,以到达易维护、可扩展、高复用的目的。
既然OOP这么多优点,那么经常被大家提起的面向切面编程(AOP)是什么回事呢,下面我们就一起来看一下。

AOP定义

第一步还是要知道aop是什么,先个来自维基百科的解释:

面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计、观点导向编程、剖面导向程序设计)是计算机科学中的一个术语,指一种程序设计范型。
侧面的概念源于对面向对象的程序设计的改进,但并不只限于此,它还可以用来改进传统的函数。

其从主关注点中分离出横切关注点是面向侧面的程序设计的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来.
业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过侧面来封装、维护. 这样原本分散在在整个应用程序中的变动就可以很好的管理起来。

tip

确实有点那么不太清晰,有点乱。不过在乱之前,我们可以选能理解的部分先看一下:

  • 侧面(也就是切面) 用来描述分散在对象、类或函数中的横切关注点
    重点在这,分散在对象中的横切关注点,可以猜一下是什么,应该就是不同对象之间公用的部分
  • 侧面的概念源于对面向对象的程序设计的改进,它还可以用来改进传统的函数. AOP 显然不是OOP的替代品,是OOP的一种补充。
  • 从主关注点中分离出横切关注点是面向侧面的程序设计的核心概念。
    具体到业务项目中来说,主关注点就是业务逻辑了。针对特定领域问题代码的调用,就是AOP要关注的部分

简而言之,AOP是针对业务处理过程中的切面(即非业务逻辑部分,例如错误处理,埋点,日志等)进行提取.
它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果(目的是降低耦合)。
具体到实现来说就是通过动态的方式将非主关注点部分插入到主关注点(一般是业务逻辑中)

说了这么多,可能不太明白,还是一起看代码吧。

埋点场景

很普遍的这么个场景,需要点击按钮之后进行信息上报。 假设我们有这么个logger的工具,可以进行上报:

const logger = console.log
//引入即可使用
logger('按钮被点击了')

那么,我们直接撸起来吧:

const doSomething = ()=>{console.log('doSomething')
} 
let clickHandler = ()=>{logger('doSomething之前')// n行代码 doSomething() logger('doSomething之后')//n 行代码
}

看起来也没什么的,简单粗暴。
如果有30个按钮,每个业务逻辑不同,都需要埋这个点(假设打点信息一致)。
我们30个函数里面,都要手动写这个方法的话,这也太坑爹了吧。
主要是与业务代码严重耦合,哪天不小心动了点其他内容,手抖误删了,就gg了。
后续维护的时候,简直噩梦。
仔细看一下,这不就是符合AOP的使用前提吗,那么试试AOP吧。

关注点划分

根据前面提的,可以划分下关注点。

主关注点侧关注点
业务逻辑(doSomething)埋点信息 logger

前面提到AOP关注的是步骤具体到例子来说其实就是插入logger的步骤。
插入时机无非时业务逻辑执行之前或者之后的阶段。
具体实现起来也不那么困难

实现思路

具体到js来说,由于语言本身的特性,天生就具有运行时动态插入逻辑的能力。
重点在于在原函数上增加其他功能并不改变函数本身。

毕竟函数可以接受一切形式的参数,当然函数也不例外了。
当传入一个函数的时候,我们要对其操作的余地就很大了,
保存原函数,然后利用后续参数加上call或apply,就可以达到我们的目的。
此外为了给函数都增加一个属性,我们在原型上操作就行了。

经典before或者after的实现

网上太多类似实现了,直接看代码好了:

// action 即为我们的侧关注点,即logger
Function.prototype.after = function (action) {//保留当前函数,这里this指向运行函数即clickHandlervar func = this;// return 被包装过的函数,这里就可以执行其他功能了。// 并且该方法挂在Function.prototype上,// 被返回的函数依然具有after属性,可以链式调用return function () {// 原函数执行,这里不考虑异步var result = func.apply(this, arguments);// 执行之后的操作action.apply(this,arguments);// 将执行结果返回return result;};
};
// before 实现类似,只不过执行顺序差别而已
Function.prototype.before = function (action) {var func = this;return function () {action.apply(this,arguments);return func.apply(this, arguments);};
};

那么我们使用AOP改造之后的代码就如下了:

const doSomething = ()=>{console.log('doSomething')
} 
let clickHandler = ()=>{// n行代码 doSomething() //n 行代码
}
clickHandler = clickHandler.before(()=>{logger('doSomething之前')
}).after(()=>{logger('doSomething之后')
})
clickHandler() // 执行结果和预期一致

到这里就实现了面向切面编程,我们的业务逻辑里面只管业务本身,侧关注点通过这种方式来动态引入,与主逻辑解耦,更加纯净、易于维护。

结束语

到这里,简单的AOP就介绍完成了。利用这种模式结合我们js本身的特性,可以尝试更多的可能。 例如我们react中常见的HOC、es7的装饰者模式、HOF等,很多时候不得不感叹大牛们思想的精髓,会让我们有种顿悟的感觉。本文抛砖引玉,共同学习啦,对自己是总结和提高,更希望能帮助到需要的小伙伴。更多文章请移步我的博客

参考文章

AllyTeam - 用AOP改善javascript代码
深入浅出 Javascript Decorators 和 AOP 编程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367424.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows和linux允许分片,请问hadoop的hdfs文件系统和本地windows文件系统或linux文件系统是什么关系啊,谢谢...

虚拟文件系统 Virtual File Systems(VFS)Linux 是近年来发展起来的一种新型的操作系统,其最重要的特征之一就是支持多种文件系统,使其更加灵活,从而与许多其它的操作系统共存。Linux支持ext,ext2,xia,minix…

201771010120 苏浪浪 《面向对象程序设计(java)》第二周学习总结

理论知识总结 第三章Java基本程序设计结构 1、基本知识:(1)标识符:是由字母、下划线、美元符号和数字组成,且第一个符号不能为数字。(2)关键字:剧啊语言中被赋予特定意义的一些单词。…

Apache Camel简介

Apache Camel是著名的企业集成模式的开源实现。 Camel是一个路由和中介引擎,可以帮助开发人员以各种领域特定语言(DSL)(例如Java,Spring / XML,scala等)创建路由和中介规则。 骆驼用途广泛 Cam…

《架构即未来》读后感

前言 有将近2年没有写文章了,首先是不知道分享什么,其次就是工作也比较忙,闲暇的时间要么玩游戏、听小说、看电影,虽然也有看书但其实也并不多,以上也都是为了我的懒惰所找的一些借口。 虽然到现在为止也看了百来本书&…

qt结构体嵌套结构体方法_9.2 C++结构体类型变量

C定义结构体类型变量的方法 1、先声明结构体类型再定义变量名,在定义了结构体变量后,系统会为之分配内存单元。struct Student{ //自定义结构体变量int num;//学号char sex;//性别int age;//年龄};2、在声明类型的同时定义变量 一般形式为struct 结构体名…

Vue解析--如何应对面试官提问

近期不断面试中,面试官都会提一些关于Vue相关的源码和“全家桶”之类的问题。那么针对这些提问,我们应该如何更好应答呢?在这里我把对Vue的理解整理出来供大家来参考。 1.Vue是什么? Vue是一套构建用户界面的渐进式框架&#xf…

搭建自动安装的linux,RedHat7搭建无人值守自动安装Linux操作系统(PXE+Kickstart)

Kickstart服务器IP: 192.168.136.253 掩码:255.255.255.0 网关:192.168.136.2 DNS:192.168.136.2安装部署yum源服务器参考 http://www.cnblogs.com/edward2013/p/5020113.html安装部署DHCP服务器# yum -y install dhcp修改配置文件# vi…

Numpy数组的保存与读取方法

1. 数组以二进制格式保存 np.save和np.load是读写磁盘数组数据的两个主要函数。默认情况下,数组以未压缩的原始二进制格式保存在扩展名为npy的文件中,以数组a为例 np.save("filename.npy",a)b np.load("filename.npy")利用这种方法…

Java开发人员的Erlang

您可能没有注意到,但是距离我上次发布博客已经过去了几个星期。 原因是我的Soleus骨折了,而我的腿也石膏了。 不能动弹,我认为调查完全不同的东西是个好主意–要么看那天的电视,要么,尽管Kojak和Magnum PI的重播很诱人…

20165339第六周学习总结

课本知识点总结 第八章 String类 使用String类声明对象并创建对象 String s new String("We are students"); String t new String("We are students"); String (char a[])用一个字符数组a创建一个String对象 char a[] {J,a,v,a}; String s new String(a)…

keil5用jlink不到芯片_洛达芯片检测

安卓手机下载一个络达官方的刷机软件然后连接上耳机,打开软件,就可以看到耳机芯片的相关信息。软件下载地址:https://pan.baidu.com/s/1MOXjkHv1wfxWWIVdcsMSFg 提取码: tasc我们的耳机都是络达芯片,不怕你检测,希望用…

层次和约束:项目中使用vuex的3条优化方案

问题描述 使用vuex的store的过程中,发现了一些不是很优雅的地方: store层module太多,找state、getter、mutation、action对应的module比较慢。 组件里面mapGetters、mapActions、mapMutations过多,分不清getter、action、mutati…

linux脚本编写规则,shell脚本编写守则

现在centos7中使用的是bash软件,通过以下命令可以查看bash版本:[rootlocalhost ~]# cat /etc/redhat-release #查看系统的版本CentOS Linux release 7.5.1804 (Core) #我这里使用的是centos 7.5 1804[rootlocalhost ~]# bash --version #查看bash的版本G…

luogu P2516 [HAOI2010]最长公共子序列

传送门 首先那个\(O(n^2)\)的dp都会吧,不会自己找博客或者问别人,或是去做模板题(误) 对以下内容不理解的,强势推荐flash的博客 我们除了原来记录最长上升子序列的\(f_{i,j}\),再记\(g_{i,j}\)表示到\(i,j\)时的最长上升子序列个数,同时设两个字符串为\(A,B\) 若\(A_iB_j\) ,则…

怎么让员工服从管理_为什么现在的员工执行力和服从性越来越差,管理一严格就辞职?...

当有负面情绪的时候,不要说。管好自己的嘴,有时候做哑巴,是一种境界。现在的企业很多都存在这个问题,员工执行力越来越差,服从性也越来越差,管理者稍微一严格,员工就会辞职走人,留不…

Spring Data REST的实际应用

什么是春天数据休息? spring-data-rest是spring-data项目的新增功能,它是一个框架,可帮助您将实体直接作为RESTful Web服务端点公开。 与rails,grails或roo不同,它不会生成任何实现此目标的代码。 spring data-rest支持…

2018上半年掘金微信群日报优质文章合集:前端篇

在掘金微信交流群里的小伙伴们,你们每天都还在坚持读小报吗?如果你的回答是yes,那真的要给你点一万个赞了?能坚持这么久,真的很优秀噢!(嗯,每天坚持给大家收集文章的小饼也很优秀?&#xff09…

linux运维笔试题目,linux运维相关的笔试题目_笔试题目

一、Linux系统和shell1、写一个sed命令,修改/tmp/input.txt文件的内容,要求:①删除所有空行;②在非空行前面加一个“AAA”,在行尾加一个“BBB”,即将内容为“11111”的一行改为:“AAA11111BBB”…

python之路--day17-shelve,xml和re模块

shelve模块 shelve模块只有一个open函数,返回类似字典的对象,可读可写,key必须为字符串,而值可以是python所支持的数据类型 1 import shelve2 # info1{age:18,height:180,weight:80}3 # info2{age:73,height:150,weight:80}4 #5 #…

20172314 2018-2019-1《程序设计与数据结构》第一周学习总结

教材学习内容总结 概述 软件工程:是一门关于高质量软件开发的技术和理论的学科,用来控制开发过程,实现高质量的软件。软件工程的目标:正确性、可靠性、健壮性、可用性、可维护性、可重用性、可移植性、运行效率。 对于可靠性和健壮…