• javascript设计模式:装饰者模式


    装饰者模式 (Decorator Pattern)又称装饰器模式,在不改变原对象的基础上,通过对其添加属性或方法来进行包装拓展,使得原有对象可以动态具有更多功能。

    本质是功能动态组合,即动态地给一个对象添加额外的职责,就增加功能角度来看,使用装饰者模式比用继承更为灵活。好处是有效地把对象的核心职责和装饰功能区分开,并且通过动态增删装饰去除目标对象中重复的装饰逻辑。

    一、装饰者模式生活实例

    房屋装修,当毛坯房建好的时候,已经可以居住了,虽然不太舒适。一般我们自己住当然不会住毛坯,因此我们还会通水电、墙壁刷漆、铺地板、家具安装、电器安装等等步骤,让房屋渐渐具有各种各样的特性,比如墙壁刷漆和铺地板之后房屋变得更加美观,有了家具居住变得更加舒适,但这些额外的装修并没有影响房屋是用来居住的这个基本功能,这就是装饰的作用。

    喝的奶茶,除了奶茶之外,还可以添加珍珠、波霸、椰果、仙草、香芋等等辅料,辅料的添加对奶茶的饮用并无影响,奶茶喝起来还是奶茶的味道,只不过辅料的添加让这杯奶茶的口感变得更多样化。

    比如去咖啡厅喝咖啡,点了杯摩卡之后我们还可以选择添加糖、冰块、牛奶等等调味品,给咖啡添加特别的口感和风味,但这些调味品的添加并没有影响咖啡的基本性质,不会因为添加了调味品,咖啡就变成奶茶。

    在类似场景中,这些例子有以下特点:

    1. 装饰不影响原有的功能,原有功能可以照常使用;
    2. 装饰可以增加多个,共同给目标对象添加额外功能;

    二、代码实现

    function OriginHouse() { }
    
    OriginHouse.prototype.getDesc = function () {
        console.log("空房子");
    }
    
    function Furniture(house) {
        this.house = house;
    }
    Furniture.prototype.getDesc = function () {
        this.house.getDesc();
        console.log("搬入家具");
    }
    
    function Painting(house) {
        this.house = house;
    }
    
    Painting.prototype.getDesc = function () {
        this.house.getDesc();
        console.log("刷房子")
    }
    let house = new OriginHouse()
    house = new Furniture(house)
    house = new Painting(house)
    
    // house.getDesc()
    
    var originHouse = {
        getDesc() {
            console.log("origin house");
        }
    }
    
    function furniture() {
        console.log("furniture");
    }
    
    function painting() {
        console.log("painting");
    }
    originHouse.getDesc = function () {
        var getDesc = originHouse.getDesc;
        return function () {
            getDesc();
            furniture();
            painting();
        }
    }()
    originHouse.getDesc();

     

     在表现形式上,装饰者模式和适配器模式比较类似,都属于包装模式。在装饰者模式中,一个对象被另一个对象包装起来,形成一条包装链,并增加了原先对象的功能。

    三、实战中的装饰者模式

    • 给浏览器事件添加新功能

    之前介绍的添加装饰器函数的方式,经常被用来给原有浏览器或 DOM 绑定事件上绑定新的功能,比如在 onload 上增加新的事件,或在原来的事件绑定函数上增加新的功能,或者在原本的操作上增加用户行为埋点:

    window.onload = function() {
        console.log('原先的 onload 事件 ')
    }
    
    /* 发送埋点信息 */
    function sendUserOperation() {
        console.log('埋点:用户当前行为路径为 ...')
    }
    
    /* 将新的功能添加到 onload 事件上 */
    window.onload = function() {
        var originOnload = window.onload
        return function() {
            originOnload && originOnload()
            sendUserOperation()
        }
    }()
    
    // 输出: 原先的 onload 事件
    // 输出: 埋点:用户当前行为路径为 ...

    可以看到通过添加装饰函数,为 onload 事件回调增加新的方法,且并不影响原本的功能,我们可以把上面的方法提取出来作为一个工具方法:

    function originDecorationFn(originObj, originKey, fn) {
        originObj[originKey] = function() {
            var originFn = originObj[originKey];
            return function() {
                originFn && originFn();
                fn();
            }
        }()
    }
    window.onload = function() {
        console.log('原先的 onload 事件 ')
    }
    
    function sendUserOperation() {
        console.log('埋点:用户当前行为路径为 ...');
    }
    originDecorationFn(window, 'onload', sendUser, sendUserOperation);
  • 相关阅读:
    硬盘数据丢失,到底该如何修复?
    硬盘数据丢失,到底该如何修复?
    CMD命令操作MySql数据库详解
    CMD命令操作MySql数据库详解
    Java中Calendar.DAY_OF_WEEK、DAY_OF_MONTH需要减一的原因
    Java中Calendar.DAY_OF_WEEK、DAY_OF_MONTH需要减一的原因
    java中JFrame类中函数addWindowListener(new WindowAdapter)
    java中JFrame类中函数addWindowListener(new WindowAdapter)
    关于java数据库章节connection连接不成功的时候!!!
    树莓派4之点亮led
  • 原文地址:https://www.cnblogs.com/Nyan-Workflow-FC/p/13042461.html
Copyright © 2020-2023  润新知