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

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

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

装饰器模式的定义

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

传统的 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>
相关文章
|
7月前
|
存储 Web App开发 运维
发布、部署,傻傻分不清楚?从概念到实际场景,再到工具应用,一篇文章让你彻底搞清楚
部署和发布是软件工程中经常互换使用的两个术语,甚至感觉是等价的。然而,它们是不同的! • 部署是将软件从一个受控环境转移到另一个受控环境,它的目的是将软件从开发状态转化为生产状态,使得软件可以为用户提供服务。 • 发布是将软件推向用户的过程,应用程序需要多次更新、安全补丁和代码更改,跨平台和环境部署需要对版本进行适当的管理,有一定的计划性和管控因素。
1610 1
|
存储 缓存 搜索推荐
想要快速地拥有Sitecore DXP平台!这九个开发大坑一定要避开!
随着互联网技术的深入的发展,人们对于个性化的渴望已经达到了新的阈值,这也让以数字洞察力、个性化体验为名的Sitecore DXP平台成为了品牌们竞相追捧的新宠。而在这样的需要背景下,一众新手企业纷纷投身市场,想要分一杯羹。但是经验不足的新人入场,难免会带来不少麻烦,甚至引发了人们对于Sitecore性能的质疑。
|
设计模式 JavaScript 前端开发
基于装饰器——我劝你不要在业务代码上装逼!!!(下)
基于装饰器——我劝你不要在业务代码上装逼!!!(下)
|
设计模式 SQL Java
有点狠有点猛,我用责任链模式重构了业务代码
文章开篇,抛出一个老生常谈的问题,学习设计模式有什么作用? 设计模式主要是为了应对代码的复杂性,让其满足开闭原则,提高代码的扩展性 另外,学习的设计模式 一定要在业务代码中落实,只有理论没有真正实施,是无法真正掌握并且灵活运用设计模式的 这篇文章主要说 责任链设计模式,认识此模式是在读 Mybatis 源码时, Interceptor 拦截器主要使用的就是责任链,当时读过后就留下了很深的印象(内心 OS:还能这样玩)
|
数据安全/隐私保护
分享五款没什么名气却意外好用的软件
噔噔噔噔,作为一个黑科技软件爱好者,电脑里肯定是不会缺少这方面的东西,今天的5款优质软件闪亮登场了。
167 0
分享五款没什么名气却意外好用的软件
|
消息中间件 Kubernetes Cloud Native
记一次内部分享——瞎扯淡
记一次内部分享——瞎扯淡
记一次内部分享——瞎扯淡
|
安全 PHP
PHP编程模拟病毒传播过程,告诉你为什么不能随意出门溜达?
由于近期新冠状肺炎病毒的传播,我们看到上图中的病毒传播过程介绍。同时,为了让这个过程更加的直观,我们用计算机编程模拟了一个简单的模型来演示,通过视觉效果给大家做个演示!
445 0
PHP编程模拟病毒传播过程,告诉你为什么不能随意出门溜达?
|
Java 关系型数据库
你写的代码,是别人的噩梦吗?
Frank,是来自阿里国际技术事业部的高级技术专家,从业十年,也是一位英语说到飞起的型男。今天他将与大家聊聊关于企业应用架构实践的话题。
3335 0
|
.NET C#
代码无错就是优?简单工厂模式 C#
还是那几句话: 学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 废话不多说,直接进入正题: 现在给你一道面试题,如下: 请用C++,C#,Java或VB.NET等任意一种面向对象语言实现一个计算机控制台程序,要求输入任意两个数字和一个运算符号,得到结果。
1229 0