基于装饰器——我劝你不要在业务代码上装逼!!!(上)

简介: 基于装饰器——我劝你不要在业务代码上装逼!!!(上)

基于装饰器——我劝你不要在业务代码上装逼!!!

装饰器模式的定义

  • • 在传统的面向对象语言中,给对象添加功能常使用继承的方式,但继承的方式并不灵活,会带来一些许多问题,如:超类和子类存在强耦合性,也就是说当改变超类时,子类也需要改变。
  • • 而装饰器模式的出现改变的这种方式,装饰器模式可在不改变现有对象解构的基础上,动态地为对象添加功能

传统的 JavaScript 装饰器

var plane = {
    fire: function () {
        console.log("普通子弹");
    },
};
var missleDecorator = function () {
    console.log("发射导弹");
};
var atomDecorator = function () {
    console.log("发射原子弹");
};
var fire1 = plane.fire;
plane.fire = function () {
    fire1();
    missleDecorator();
};
var fire2 = plane.fire;
plane.fire = function () {
    fire2();
    atomDecorator();
};
plane.fire();
/**
普通子弹
发射导弹
发射原子弹
 */

装饰函数

  • • 在 JavaScript 中,几乎一切都是对象,其中函数也被成为对象,在平时的开发中,我们都在和函数打交道。在给对象扩展属性和方法时,很难在不改动原功能函数的情况下,给函数添加一些额外的功能,最直接的粗暴方式就是直接改写函数,但这是最差的方式,这违反了开放——封闭原则。
  • • 如下:
function a(){
    console.log(1);
}
// 改写:
function a(){
    console.log(1);
    // 新功能
    console.log(2);
}
  • • 很多时候,我们都不想去触碰之前的一些代码,但需要添加功能,所以如果需要在不改变原功能函数的情况下,给函数添加功能。可使用以下方式:
  • • 要想完美的给函数添加功能,可使用 AOP 来装饰函数
  • • AOP:一种编程规范,通过将关注点从主业务逻辑中剥离出来并单独处理,以此来提高代码的可读性和重用性。
  • • 如下:
Function.prototype.before = function (beforeFn) {
    var _self = this;
    return function () {
        beforeFn.apply(this, arguments);
        return _self.apply(this, arguments);
    };
};
Function.prototype.after = function (afterFn) {
    var _self = this;
    return function () {
        var ret = _self.apply(this, arguments);
        afterFn.apply(this, arguments);
        return ret;
    }
}
// before 和 after 函数都接收一个函数作为参数,这个函数也就是新添加的函数(里面也就是要添加的新功能逻辑)。
// 而before 和 after 函数区别在于在是原函数之前执行还是之后执行。
  • • AOP 函数的使用
Function.prototype.before = function (beforeFn) {
    var _self = this;
    return function () {
        beforeFn.apply(this, arguments);
        return _self.apply(this, arguments);
    };
};
Function.prototype.after = function (afterFn) {
    var _self = this;
    return function () {
        var ret = _self.apply(this, arguments);
        afterFn.apply(this, arguments);
        return ret;
    }
}
var o1 = function(){
    console.log('1');
}
var o2 = function(){
    console.log('2');
}
var o3 = function(){
    console.log('3');
}
var desctor = o1.after(o2);
desctor = desctor.after(o3);
desctor(); // 1 2 3
/**
var desctor = o1.after(o2);
desctor = desctor.after(o3);
desctor();
1
2
3
var desctor = o1.before(o2);
desctor = desctor.before(o3);
desctor();
3
2
1
var desctor = o1.after(o2);
desctor = desctor.before(o3);
desctor();
3
1
2
var desctor = o1.before(o2);
desctor = desctor.after(o3);
desctor();
2
1
3
 */

AOP的应用

1.数据上报

  • • 在程序开发中,当业务代码开发完后,在结尾时需要加很多的日志上报的代码,普遍我们会去改已经之前封装好的功能函数。其实这并不是一个好的方式,那如何在不直接修改之前函数的基础上添加日志上报功能呢?
  • • 如下:
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>AOP日志上报</title>
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <script src="https://unpkg.com/vue@3.2.20/dist/vue.global.js"></script>
    </head>
    <body>
        <div id="app">
            <button class="btn" @click="handler">Button</button>
            <p id="tt">{{message}}</p>
        </div>
    </body>
</html>
<script type="text/javascript">
    // log report
    const { reactive, ref, createApp } = Vue;
    const app = createApp({
        setup() {
            const message = ref("未点击");
            const count = ref(0);
            Function.prototype.before = function (beforeFn) {
                var _self = this;
                return function () {
                    beforeFn.apply(this, arguments);
                    return _self.apply(this, arguments);
                };
            };
            Function.prototype.after = function (afterFn) {
                var _self = this;
                return function () {
                    var ret = _self.apply(this, arguments);
                    afterFn.apply(this, arguments);
                    return ret;
                };
            };
            function handler() {
                message.value = `已点击${++count.value}`;
            }
            handler = handler.after(log);
            function log() {
                message.value = message.value + "-----> log reported";
                console.log("log report");
            }
            return {
                message,
                handler,
            };
        },
    });
    app.mount("#app");
</script>
目录
打赏
0
0
0
0
23
分享
相关文章
揭秘企业数据智能创新奥秘 | 2023云栖大会倚天专场
【倚天专场】邀请了弹性计算、操作系统、平头哥、ARM中国等专家为大家解读阿里云倚天ECS实例最新进展,包括云原生处理器最新技术、龙蜥+倚天软硬件结合、倚天ECS实例最佳实践等话题,为客户上云提供一个更具“性价比”的选择,加速企业数据智能创新。
Java代码居然能搞定自动化温控
Java代码居然能搞定自动化温控
174 0
Istio中如何限流?
在 Istio 中,可以使用 Envoy 的内置限流机制来限制服务的流量。Envoy 是 Istio 中的数据平面代理,它可以在服务之间进行流量管理和控制。
653 0
AI语音机器人安装方法 AI机器人安装代码
AI语音机器人安装方法 AI机器人安装代码
123 2
发布、部署,傻傻分不清楚?从概念到实际场景,再到工具应用,一篇文章让你彻底搞清楚
部署和发布是软件工程中经常互换使用的两个术语,甚至感觉是等价的。然而,它们是不同的! • 部署是将软件从一个受控环境转移到另一个受控环境,它的目的是将软件从开发状态转化为生产状态,使得软件可以为用户提供服务。 • 发布是将软件推向用户的过程,应用程序需要多次更新、安全补丁和代码更改,跨平台和环境部署需要对版本进行适当的管理,有一定的计划性和管控因素。
2888 1
|
9月前
|
Netty Pipeline详解!
本文深入剖析了 Netty 的管道(Pipeline)设计,Netty 是一个基于 Java NIO 的高性能网络应用框架。文章详细介绍了 Pipeline 的原理、源码及设计思维。Pipeline 作为事件处理链条,包含多个处理器,负责处理入站和出站事件。核心组件包括 `ChannelPipeline`、`ChannelHandler` 和 `ChannelHandlerContext`。Netty 通过链式结构和上下文管理实现了高效的事件传播机制,具备高吞吐量和低延迟的特点。本文还探讨了 Pipeline 的职责分离、链式处理、高内聚低耦合等设计原则,为高性能网络编程提供了宝贵的启示。
261 8
10款好用的开源 HarmonyOS 工具库
HarmonyOS NEXT 正式版即将发布,你在学习鸿蒙的过程还有哪些好用的工具库吗,欢迎分享给V 哥,关注威哥爱编程,一起学习鸿蒙开发。
518 4
从中序与后序遍历序列构造二叉树
【10月更文挑战第13天】这段内容介绍了一种基于中序和后序遍历序列构建二叉树的方法。通过识别后序遍历中的根节点,并利用中序遍历划分左右子树,进而递归构建整棵树。文中提供了具体示例及Python代码实现,并分析了该方法的时间与空间复杂度。
260 0
在Linux中,如何改IP、主机名、DNS?
在Linux中,如何改IP、主机名、DNS?
[golang]推送钉钉机器人消息
[golang]推送钉钉机器人消息
159 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等