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

本是古典 何须时尚 2022-10-02 14:53 255阅读 0赞

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

先看一个例子

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1c3RfY3ls_size_16_color_FFFFFF_t_70

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

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1c3RfY3ls_size_16_color_FFFFFF_t_70 1

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

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

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

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

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

  1. class Appearance {
  2. show () {}
  3. }
  4. class Person extends Appearance {
  5. constructor() {
  6. super();
  7. }
  8. show () {
  9. console.log("我要穿衣服了!")
  10. }
  11. }
  12. class Decorate extends Appearance {
  13. constructor() {
  14. super();
  15. this.component = null;
  16. }
  17. setDecorate(component) {
  18. this.component = component;
  19. }
  20. show() {
  21. if (this.component !== null) {
  22. this.component.show();
  23. }
  24. }
  25. }
  26. class TShirts extends Decorate {
  27. constructor() {
  28. super();
  29. }
  30. show () {
  31. console.log(this.component);
  32. this.component.show();
  33. console.log("穿上TShirts")
  34. }
  35. }
  36. class Jeans extends Decorate {
  37. constructor() {
  38. super();
  39. }
  40. show () {
  41. this.component.show();
  42. console.log("穿上Jeans")
  43. }
  44. }
  45. class Phone extends Decorate {
  46. constructor() {
  47. super();
  48. }
  49. show () {
  50. this.component.show();
  51. console.log("带上手机")
  52. }
  53. }
  54. const cyl = new Person();
  55. const ts = new TShirts();
  56. const je = new Jeans();
  57. const ph = new Phone();
  58. ts.setDecorate(cyl);
  59. je.setDecorate(ts);
  60. ph.setDecorate(je);
  61. ph.show();

2019062122421132.png

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

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

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1c3RfY3ls_size_16_color_FFFFFF_t_70 2

  1. class Circle {
  2. draw() {
  3. console.log("画圆");
  4. }
  5. }
  6. class Decorator {
  7. constructor(circle) {
  8. this.circle = circle;
  9. }
  10. draw() {
  11. this.circle.draw();
  12. this.setRedBorder();
  13. }
  14. setRedBorder() {
  15. console.log("加上红色的边框")
  16. }
  17. }
  18. const c = new Circle();
  19. const d = new Decorator(c);
  20. d.draw();

20190621230151153.png

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

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

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

20190621232659927.png20190621232727283.png

然后就可以运行代码了。

  1. @demoDec
  2. class Demo {}
  3. function demoDec(target) {
  4. target.flag = true;
  5. }
  6. console.log(Demo.flag);

20190621232952829.png

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

  1. Demo = demoDec(Demo) || Demo;

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

  1. function readOnly(target, name, descriptor) {
  2. descriptor.writable = false;
  3. return descriptor;
  4. }
  5. class Demo {
  6. @readOnly
  7. name() {
  8. return "cyl"
  9. }
  10. }
  11. const d = new Demo();
  12. d.name = () => {};
  13. console.log(d.name());

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

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

对装饰器的部分解释

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1c3RfY3ls_size_16_color_FFFFFF_t_70 3

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

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

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

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

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

发表评论

表情:
评论列表 (有 0 条评论,255人围观)

还没有评论,来说两句吧...

相关阅读

    相关 设计模式——装饰模式

    > 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 >

    相关 设计模式-装饰模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个

    相关 设计模式----装饰模式

           今天来学习分析下装饰器模式,首先我们分析它的名字应该要知道这个模式的作用应该就是类似我们用装饰品一样,随用随取的特点。发挥你的想象,如果我们写的程序能有这样的特点