您的位置:首页 > 编程语言

面向切面编程(AOP)

2019-05-25 22:59 766 查看

面向切面编程(Aspect-Oriented Programming/AOP) 解决的是 cross-cutting concerns 问题。比如同一段代码在不同模块中重复,又不能简单地通过抽取公共方法的方式来达到重构,比如日志与参数校验。

以下是展示这一编程思想的一段伪代码:

function mainProgram()
{
var x =  foo();
doSomethingWith(x);
return x;
}

aspect logging
{
before (mainProgram is called):
{
log.Write("entering mainProgram");
}

after (mainProgram is called):
{
log.Write(  "exiting mainProgram with return value of "
+ mainProgram.returnValue);
}
}

aspect verification
{
before (doSomethingWith is called):
{
if (doSomethingWith.arguments[0] == null)
{
throw NullArgumentException();
}

if (!doSomethingWith.caller.isAuthenticated)
{
throw Securityexception();
}
}
}

代码进行编译转换后实际成为这样子:

function mainProgram()
{
log.Write("entering mainProgram");

var x = foo();

if (x == null) throw NullArgumentException();
if (!mainProgramIsAuthenticated()) throw Securityexception();
doSomethingWith(x);

log.Write("exiting mainProgram with return value of "+ x);
return x;
}

与 Mixin 的差别

Mixin 中代码与宿主无关,可向宿主添加做生意多的功能。装饰器是侵入式的,将宿主进行代理,对外提供的接口不变,可在相应逻辑运行前后进行拦截操作。

装饰器

装饰器(decorator pattern)可认为是一种面向切面的编程。一个装饰器可运用于类(class)属性(property),方法(method)以及参数等(parameter)。加上装饰器后,可用于对目标对象的日志处理,权限检查等与业务无关的操作。

JavaScript 中的实现

装饰器如其如,类似于给方法添加一个修饰,具体的功能在装饰器中实现,所有应用了该装饰器的方法都会带上相应的功能。

主流强类型语言比如 Java,C# 中装饰器由来已久,但 JavaScript 其还处于 stage 2 proposal 阶段。不过可通过 TypeScript 来使用,编译选项中开启

experimentalDecorators
参数。

{
"compilerOptions": {
"experimentalDecorators": true
}
}

装饰器运用最为典型的是 Angular。其整体框架大量使用装饰器来定义各组件模块,同时控制相应组件及模块的行为。

@Component({
selector: 'example-component',
template: '<div>Woo a component!</div>',
})
export class ExampleComponent {
constructor() {
console.log('Hey I am a component!');
}
}

其他应用场景比如将路由的定义使用装饰器写在 Controller 上,参见 midway 框架 - 路由装饰器

import { provide, controller, inject, get } from 'midway';

@provide()
@controller('/user')
export class UserController {

@inject('userService')
service: IUserService;

@get('/:id')
async getUser(ctx): Promise<void> {
const id: number = ctx.params.id;
const user: IUserResult = await this.service.getUser({id});
ctx.body = {success: true, message: 'OK', data: user};
}
}

相关资源

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: