是什么
面向切面编程(AOP
)是Java
常用编程思想,它的作用是在某个函数上进行切割,可以在函数执行 前 / 中 / 后 添加其它逻辑代码。
AOP
编程的好处是遵循单一原则,不会修改原函数内部的代码就可以改变原函数的逻辑。
AOP
装饰函数的技巧在实际开发中非常有用。无论是业务代码还是框架层面,我们都可以把行为依照职责分成粒度更细的函数,随后通过装饰把它们合并到一起,这有助于我们编写一个松耦合和高复用性的系统。
原型链实现 AOP
/**
* 切入前代码
* @param {Function} fn
* @param {Function} beforeFn
* @returns
*/
const before = function (fn, beforeFn) {
return function () {
beforeFn.apply(this, arguments);
return fn.apply(this, arguments);
}
}
/**
* 切入后代码
* @param {Function} fn
* @param {Function} beforeFn
* @returns
*/
const after = function (fn, afterFn) {
return function () {
let agent = fn.apply(this, arguments);
afterFn.apply(this, arguments);
return agent;
}
}
let logic = function () {
console.log('业务代码')
}
logic = before(logic, function () {
console.log('切入前代码')
})
logic = after(logic, function () {
console.log('切入后代码')
})
logic();
// 切入前代码
// 业务代码
// 切入后代码
实现职责链模式
用AOP
实现职责链即简单又巧妙,这种把函数叠在一起的方式,同时也叠加了函数的作用域。
最大优点解耦了请求发送者和N个接收者之间复杂关系。
假设:一个电商网站,对缴纳定金的用户有不同的优惠政策。已经支付过 500 元定金的用户会收到 100 元的优惠券,支付 200 元定金的用户可以收到 50 元的优惠券,没有支付定金的用户则为普通的购买模式。没有优惠券,且在库存有限的情况下不一定保证能买到。
let order500 = function (orderType, pay, stock) {
if (orderType === 1 && pay) {
console.log('500元定金,得到100优惠券');
} else {
return 'nextSuccessor';
}
}
let order200 = function (orderType, pay, stock) {
if (orderType === 2 && pay) {
console.log('200元定金,得到50优惠券');
} else {
return 'nextSuccessor';
}
};
let orderNormal = function (orderType, pay, stock) {
if (stock > 0) {
console.log('普通购买,无优惠券');
} else {
console.log('手机库存不足');
}
};
Function.prototype.after = function (fn) {
let _this = this
return function () {
let ret = _this.apply(this, arguments)
if (ret === 'nextSuccessor') return fn.apply(this, arguments)
return ret
}
}
let order = order500.after(order200).after(orderNormal)
order(1, true, 500); // 500元定金,得到100优惠券
order(2, true, 500); // 200元定金,得到50优惠券
order(3, true, 500); // 普通购买,无优惠券
实现装饰器模式
假设:页面中有一个登录 button 点击这个 button 会弹出登录浮层,与此同时要进行数据上报,来统计有多少个用户点击了这个登录 button。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
</head>
<body>
<button tag="login" id="button">点击</button>
</body>
<script>
Function.prototype._after = function (afterFn) {
var _self = this;
return function () {
var ret = _self.apply(this, arguments);
afterFn.apply(this, arguments);
return ret;
}
};
let showLogin = function () {
console.log('打开登录浮层')
}
let log = function () {
console.log(`上报标签为${this.getAttribute('tag')}`)
}
showLogin = showLogin._after(log)
document.getElementById('button').onclick = showLogin
// 打开登录浮层
// 上报标签为login
</script>
</html>
参考文章:
js实现AOP,面向切面编程