JavaScript -- 设计模式 结构性设计模式-装饰器模式

装饰器模式:有时我们希望给某个对象而不是整个类添加一些功能,对对象进行添加新功能,而且不改变原有的结构和功能,这个时候我们就应该想到装饰器模式。

先看一个例子

我们可以穿各种各样的衣服,而且进行各种组合,假如要你设计一下这个模式,你会如何设计了。

我们来看一下使用装饰器模式的UML类图吧。

这个类图是比较复杂的,我们先来解释一下。

最顶层的一个类,appearance是所有类的父类,它里面只有一个show函数(在JS里面可以是一个空函数)

Person类和Decorate类继承于Appearance类,其中Decorate类中,我们有一个component属性,还有一个与之配套的设置函数setComponent

TShirts Jeans Phone还有可以有其他衣服 都继承于Decorate

我们每生成一件类型的衣服 然后给它设置component 然后就相当于穿上了,当调用show函数时,类似于递归调用,具体详情可以看代码。

class Appearance {
    show () {}
}
class Person extends Appearance {
    constructor() {
        super();
    }
    show () {
        console.log("我要穿衣服了!")
    }
}
class Decorate  extends Appearance {
    constructor() {
        super();
        this.component = null;
    }
    setDecorate(component) {
        this.component = component;
    }
    show() {
        if (this.component !== null) {
            this.component.show();
        }
    }
}
class TShirts extends Decorate {
    constructor() {
        super();
    }
    show () {
        console.log(this.component);
         this.component.show();
         
         console.log("穿上TShirts")
    }
}
class Jeans extends Decorate {
    constructor() {
        super();
    }
    show () {
        this.component.show();
         
        console.log("穿上Jeans")
   }
}
class Phone extends Decorate {
    constructor() {
        super();
    }
    show () {
        this.component.show();
        console.log("带上手机")
   }
}

const cyl = new Person();

const ts = new TShirts();
const je = new Jeans();
const ph = new Phone();

ts.setDecorate(cyl);
je.setDecorate(ts);
ph.setDecorate(je);

ph.show();

很完美的实现,因为这样的实现满足开发封闭原则,当我们想增加衣服时,生成对应的实例然后调用setComponent方法即可。

 

那么在前端中,是否也需要这样复杂的设计了?很显然,我们应该对设计进行简化。

我们以画图为例,看一下一个简单版的UML类图。

class Circle {
    draw() {
        console.log("画圆");
    }
}
class Decorator {
    constructor(circle) {
        this.circle = circle;
    }
    draw() {
        this.circle.draw();
        this.setRedBorder();
    }
    setRedBorder() {
        console.log("加上红色的边框")
    }
}

const c = new Circle();

const d = new Decorator(c);
d.draw();

这个非常简单,理解起来不难。

 

接下来我们就来讨论ES7的decorator(装饰器)

首先我们安装一个插件"babel-plugin-transform-decorators-legacy",在.babelrc配置一下。

然后就可以运行代码了。

@demoDec
class Demo {}

function demoDec(target) {
  target.flag = true;
}

console.log(Demo.flag);

上面代码怎么理解了,为什么相当于装饰器了。上面代码可以翻译成这个代码

Demo = demoDec(Demo) || Demo;

上面是对类的装饰,当然还可以对方法进行装饰。

function readOnly(target, name, descriptor) {
    descriptor.writable = false;
    return descriptor;
}
class Demo {
    @readOnly
    name() {
        return "cyl"
    }
}

const d = new Demo();
d.name = () => {};
console.log(d.name());

我们使得Demo里面的name方法不允许被修改,然后运行结果如下

即使在运行过程中 name函数被修改了,但是依然是原来的函数。

对装饰器的部分解释

  • 装饰器第一个参数是 类的原型对象,上例是 Demo.prototype,装饰器的本意是要“装饰”类的实例,但是这个时候实例还没生成,所以只能去装饰原型(这不同于类的装饰,那种情况时target参数指的是类本身);
  • 第二个参数是 所要装饰的属性名
  • 第三个参数是 该属性的描述对象

回归主题,适配器模式的主要功能是给某个对象而不是整个类添加一些功能,对对象进行添加新功能,而且不改变原有的结构和功能。

ES7的语法很方便的帮助我们实现了,但是我们还是需要理解原理。在实际开发过程中,比如react的connect函数就可以使用装饰器,再比如core-decorators.js中为我们实现很多十分常用的装饰器(readOnly ,log等)。

最后我们怀着期待迎接ES7的Decorator吧!

大家可以看左边个人分类的目录,跟着一起学习。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值