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

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

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

装饰器模式的定义

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

传统的 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>
相关文章
|
6月前
|
JavaScript 前端开发 安全
TypeScript:解锁JavaScript的超级英雄模式!类型系统如何化身守护神,拯救你的代码免于崩溃与混乱,戏剧性变革开发体验!
【8月更文挑战第22天】TypeScript作为JavaScript的超集,引入了强大的类型系统,提升了编程的安全性和效率。本文通过案例展示TypeScript如何增强JavaScript:1) 显式类型声明确保函数参数与返回值的准确性;2) 接口和类加强类型检查,保证对象结构符合预期;3) 泛型编程提高代码复用性和灵活性。这些特性共同推动了前端开发的标准化和规模化。
75 0
|
6月前
|
数据安全/隐私保护 索引 Windows
这款软件的高级用法,网工直呼:真香!
这款软件的高级用法,网工直呼:真香!
|
7月前
|
Python
惊呆了!学会这一招,你的Python上下文管理器也能玩出花样来文管理器也能玩出花样来
【7月更文挑战第6天】Python的上下文管理器是资源优雅管理的关键,与with语句结合,确保资源获取和释放。通过实现`__enter__`和`__exit__`,不仅能做资源分配和释放,还能扩展实现如计时、自动重试、事务处理等功能。例如,TimerContextManager类记录代码执行时间,展示了上下文管理器的灵活性。学习和利用这一机制能提升代码质量,增强功能,是Python编程的必备技巧。
42 0
|
设计模式 JavaScript 前端开发
基于装饰器——我劝你不要在业务代码上装逼!!!(下)
基于装饰器——我劝你不要在业务代码上装逼!!!(下)
|
设计模式 SQL Java
有点狠有点猛,我用责任链模式重构了业务代码
文章开篇,抛出一个老生常谈的问题,学习设计模式有什么作用? 设计模式主要是为了应对代码的复杂性,让其满足开闭原则,提高代码的扩展性 另外,学习的设计模式 一定要在业务代码中落实,只有理论没有真正实施,是无法真正掌握并且灵活运用设计模式的 这篇文章主要说 责任链设计模式,认识此模式是在读 Mybatis 源码时, Interceptor 拦截器主要使用的就是责任链,当时读过后就留下了很深的印象(内心 OS:还能这样玩)
|
人工智能 小程序 定位技术
6个小而美的实用工具类网站!
今天来给大家科普几个小而美的,获得超高好评的实用工具类网站!
228 0
6个小而美的实用工具类网站!
|
数据安全/隐私保护
分享五款没什么名气却意外好用的软件
噔噔噔噔,作为一个黑科技软件爱好者,电脑里肯定是不会缺少这方面的东西,今天的5款优质软件闪亮登场了。
173 0
分享五款没什么名气却意外好用的软件
|
C++
爱上c++的第二天:类和对象的三大特性-封装
对只写权限,我们可以检测数据的有效性(不能让用户修改程序,即用户不能访问内部程序,以防用户进行非法操作)
120 0
|
JSON API 数据格式
工具函数(不知道你们能不能用得上)
工具函数(不知道你们能不能用得上)
热饭的测开成果盘点第二十三期:wqrfproxy自动抓包断言库
本期介绍的是一个组件,身为python的第三方库,已经被pypi收录,且国内镜像源也早已复制。也就是说可以通过pip install 来下载。这个组件就是:wqrfproxy ,它的作用是可以在正常的unittest脚本中,对app发出的请求进行断言。
热饭的测开成果盘点第二十三期:wqrfproxy自动抓包断言库