AOP 介绍
面向切片编程(AOP)是 java 常用编程思想,它的作用是在某个函数上进行切割,可以在函数执行前/后添加其他逻辑代码。
![](https://i-blog.csdnimg.cn/blog_migrate/1f7f53d42104f89ec5786657fed0e0e6.png)
前/后添加其他逻辑代码,体现在哪?
场景实战
有这样一个控制器,界面呈现呈现数据过程中增加 loading 效果
class Controllers {
loading: boolean = false;
constructor() { this.getData(); }
private getData() { new Promise(() => {}).then(() => { ... }) } } |
分析业务场景可以发现,过程中增加 loading 效果,就是在获取数据方法 getData 获取数据之前,增加 loading=true,在 getData 获取数据之后,增加 loading = false;
常规操作
class Controllers { loading: boolean = false; constructor() { this.getData(); this.getData1(); this.getData2(); } private getData() { this.loading = true; new Promise(() => {}).then(() => { // ... }).finally(() => { this.loading = false; }) } private getData1() { this.loading = true; new Promise(() => {}).then(() => { // ... }).finally(() => { this.loading = false; }) } private getData2() { this.loading = true; new Promise(() => {}).then(() => { // ... }).finally(() => { this.loading = false; }) } } |
![](https://i-blog.csdnimg.cn/blog_migrate/29c0fd2c810fb4c1ef72a9548761d8d5.png)
这样在 getData 中增加和获取数据不相关的业务操作,真的好吗?
-- 在方法中增加和该方法的逻辑不相关代码行为,被称为:方法玷污。
![](https://i-blog.csdnimg.cn/blog_migrate/c1630a26fdc8b30a8129c8becb5b3e75.png)
是不是所有的呈现数据相关的业务,都需要手动增加 this.loading ?
回调复用
写一个回调,来批量实现 loading 改变的效果
function loadingFunc(T: any, fn: Function) { return async function(...args: any[]) { (T as any)['loading'] = true; await fn.apply(T, args); (T as any)['loading'] = false; } } class Controllers { loading: boolean = false; constructor() { loadingFunc(this, this.getData)(); loadingFunc(this, this.getData1)(); loadingFunc(this, this.getData2)(); } private getData() { new Promise(() => {}).then(() => { // ... }) } private getData1() { new Promise(() => {}).then(() => { // ... }) } private getData2() { new Promise(() => {}).then(() => { // ... }) } } |
方法拦截器
// 前置拦截器 (T as any)['loading'] = true; await fn.apply(T, args); // 后置拦截器 (T as any)['loading'] = false; |
我们可以称呼这样的行为是:方法拦截器。在原生方法调用之前,我们处理了一些业务逻辑,在原生方法调用之后,紧接着处理了一些业务逻辑。通过方法拦截器,消除了方法玷污,实现了方法复用。
装饰者模式
装饰者模式的精髓在于装饰,引用《天下长河》中康熙对传教士的一句台词:“不要试图毁灭什么,而要想着为这片土地增加什么”,这就是装饰的意思。我们使用一个方法,来装饰目标函数,为目标函数,带来了前置拦截器和后置拦截器,这是装饰者模式,也是面向切面编程思想的体现。
Typescript 装饰器实现方法拦截器
function Loading(paramsValue: any) { return function (targetClassPrototype: any, methodName: any, methodDecri: PropertyDescriptor) { let targetMethodSave = methodDecri.value; methodDecri.value = async function (...args: any[]) { (this as any)[paramsValue] = true; await targetMethodSave.apply(this, args); (this as any)[paramsValue] = false; } } } class Controllers { loading: boolean = false; constructor() { this.getData(); } @Loading('loading') private getData() { new Promise(() => {}).then(() => { // ... }) } } |