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

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

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

装饰器模式的定义

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

传统的 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>
相关文章
|
3月前
|
数据采集 数据可视化 数据库连接
谁说无代码搞不定MES系统,我看smardaten能行!
我国工业制造数字化渗透率较低,为提升效率,某企业尝试使用无代码开发平台smardaten进行制造执行系统(MES)的开发,成功满足了超过80%的项目需求。smardaten以其全域数据资产管理、业务流程组装及智能分析可视化等特性,支持快速开发。平台可轻松实现数据对接、应用模块搭建、大屏展示、移动APP开发及OA门户集成等功能,大幅缩短开发周期并降低技术门槛。此外,smardaten提供SaaS试用版,便于更多企业探索无代码开发的可能性。
|
3月前
信不信?工作这么多年,还有很多网工不知道光模块光衰的正常范围?
信不信?工作这么多年,还有很多网工不知道光模块光衰的正常范围?
287 2
|
设计模式 JavaScript 前端开发
基于装饰器——我劝你不要在业务代码上装逼!!!(下)
基于装饰器——我劝你不要在业务代码上装逼!!!(下)
|
存储 编解码 数据处理
还在为搞不懂笔记本电脑参数而苦恼么?一篇文章就够啦
还在为搞不懂笔记本电脑参数而苦恼么?一篇文章就够啦
293 4
|
设计模式 SQL Java
有点狠有点猛,我用责任链模式重构了业务代码
文章开篇,抛出一个老生常谈的问题,学习设计模式有什么作用? 设计模式主要是为了应对代码的复杂性,让其满足开闭原则,提高代码的扩展性 另外,学习的设计模式 一定要在业务代码中落实,只有理论没有真正实施,是无法真正掌握并且灵活运用设计模式的 这篇文章主要说 责任链设计模式,认识此模式是在读 Mybatis 源码时, Interceptor 拦截器主要使用的就是责任链,当时读过后就留下了很深的印象(内心 OS:还能这样玩)
|
SQL 存储 Oracle
平时做开发需要掌握哪些数据库方面的知识(个人经验之谈)
平时做开发需要掌握哪些数据库方面的知识(个人经验之谈)
237 0
|
数据安全/隐私保护
分享五款没什么名气却意外好用的软件
噔噔噔噔,作为一个黑科技软件爱好者,电脑里肯定是不会缺少这方面的东西,今天的5款优质软件闪亮登场了。
162 0
分享五款没什么名气却意外好用的软件
|
消息中间件 Kubernetes Cloud Native
记一次内部分享——瞎扯淡
记一次内部分享——瞎扯淡
记一次内部分享——瞎扯淡
|
JSON Java 测试技术
如何写出让人抓狂的代码?
如何写出让人抓狂的代码?
如何写出让人抓狂的代码?
|
移动开发 小程序 IDE
小程序测试全攻略,还学不会你来找我(含实操代码)
小程序测试全攻略,还学不会你来找我(含实操代码)
537 0

相关实验场景

更多