JavaScript设计模式-装饰模式

本文深入探讨JavaScript中的装饰者模式,通过实例讲解如何在不修改原始对象的基础上动态添加职责,对比继承方式,展示装饰模式的灵活性与优势。同时,介绍了ES6装饰器的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概念

  • 在程序开发中,许多时候都并不希望某个类天生就非常庞大,一次性包含许多职责。那么我们就可以使用装饰者模式。装饰者模式可以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象。

  • 在传统的面向对象语言中,给对象添加功能常常使用继承的方式,但是继承的方式并不灵活,还会带来许多问题:

  1. 导致父类和子类之间存在强耦合性,父类改变子类也会变。
  2. 继承这种功能复用方式通常被称为“白箱复用”,“白箱”是相对可见性而言的,在继承方式中,父类的内部细节是对子类可见的,继承常常被认为破坏了封装性。
  3. 可能创建出大量的子类。

例子

装饰对象
        const plane = {
            fire: function () {
                console.log('发射普通子弹')
            }
        }
        const missileDecorator = function () {
            console.log('发射导弹')
        }
        const atomDecorator = function () {
            console.log('发射原子弹')
        }
        const fire1 = plane.fire
        plane.fire = function () {
            missileDecorator()
            fire1()
        }
        const fire2 = plane.fire
        plane.fire = function () {
            atomDecorator()
            fire2()
        }
        plane.fire()
        // 分别输出: 发射普通子弹、发射导弹、发射原子弹


        // 装饰函数
        const before = function (fn, beforefn) {
            return function () {
                // 这两段代码的意思是执行一次beforefn方法,并且利用arguments关键字把原先的参数不改变原样传递进去beforefn方法
                beforefn.apply(this, arguments)
                fn.apply(this, arguments)
            }
        }
        let a = before(
            // 方法一
            function () {
                console.log('方法一')
            },
            // 方法二
            function () {
                console.log('方法二')
            }
        )
        a()
        // 这里利用before方法,在方法一前加入方法二
        a = before(a, function () {
            console.log('方法三')
        })
        a()

ES6的装饰器

  		@atomDecorator
        @missileDecorator // 先执行
        class planeES6 {
            fire = function () {
                console.log('发射普通子弹')
            }
        }
        const planeES6Obj = new planeES6()
        planeES6Obj.fire()

        // 相当于
        // missileDecorator(planeES6)
        // atomDecorator(planeES6)
        // const planeES6Obj1 =  new planeES6()
        // planeES6Obj1.fire()


        //修饰器不仅可以修饰类,还可以修饰类的属性。
        class planeES6Fun {
            @missileDecorator
            fire = function () {
                console.log('发射普通子弹')
            }
        }
        const planeES6ObjFun = new planeES6Fun()
        planeES6ObjFun.fire()

        // 看看修饰器接受的参数
        //修饰器第一个参数是类的原型对象,第二个参数是所要修饰的属性名,第三个参数是该属性的描述对象
        function dec1(target, name, descriptor) {
            console.log('dec1target', target)
            console.log('dec1name', name)
            console.log('dec1descriptor', descriptor)
            return descriptor
        }
        function dec2(target, name, descriptor) {
            // descriptor对象原来的值如下
            // {
            //   value: specifiedFunction,
            //   enumerable: false, 是否可写
            //   configurable: true, 是否可配置 这个特性用来描述对象的某个属性是否可以用 Object.defineProperty(...) 来重新配置:
            //   writable: true 是否可枚举 for..in等
            // };
            descriptor.writable = false
            return descriptor
        }
        class Demo {
            @dec1
            methodA(num) {
                this.name = num
                console.log('method' +  this.name)
            }
            @dec2
            methodB(num) {
                this.name = num
                console.log('method2' + this.name)
            }

        }
        const d = new Demo()
        console.log('d', d)
        d.methodA = function () {
            console.log('我改了A')
        }
        d.methodA('11')
        // d.methodB = function () {
        //     console.log('我改了B')
        // }
        // 因为上面dec2配置了writable为false,所以报错
        d.methodB('22')

总结

装饰者模式能够在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责。跟继承相比,装饰者是一种更轻便灵活的做法,这是一种“即用即付”的方式。

github仓库地址:点击 设计模式例子 查看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值