Decorator 装饰器模式

今天要介绍的装饰器模式,跟之前提到过的转接器模式有点类似(但其实结果完全不一样)。

转接器模式的功能在於将让现有的物件可以透过转接器,能够实现自己没有的介面或功能。而装饰器的功能在於,维持现有物件既有的介面和功能,但是在执行细节上「加料」。

让我们来看看下面的例子。假设这里有个 Printer 的抽象类别,接着 MagazinePrinterBookPrinter 继承 Printer 并实作 print 方法

abstract class Printer {
  abstract print(): void
}

class MagazinePrinter extends Printer {
  genre: string;
  constructor(genre: string) {
    super()
    this.genre = genre
  }

  print(): string {
    return `This is a ${this.genre} magazine!`
  }
}

class BookPrinter extends Printer {
  genre: string;
  constructor(genre: string) {
    super()
    this.genre = genre
  }

  print(): string {
    return `This is a ${this.genre} book!`
  }
}

最後,我们就可以建立实例,执行 print 方法得到结果

const economyMagazine = new MagazinePrinter('economy')
const scienceBook = new BookPrinter('science')

economyMagazine.print()  // This is a economy magazine!
scienceBook.print()      // This is a science book!

问题

这时候书店老板来了,他说这个月刚好周年庆,因此希望能够在书印出来之後,也印上 "Best sell!" 的字来刺激买气。

如果只是因为要为了这一个月的促销活动,然後建立新的类别,似乎有点大费周章。这时候意旁的工程师说,不如我们就用装饰器来装饰原有的物件吧!

实作

这里我们建立一个 PromotionDecorator,同样继承 Printer,因此需要实作 print 方法。

不过比较特别的是,这里我们并不直接实作 print,而是间接依赖其他 printer 执行 print 方法,然後我们在装饰器当中加点料,像是下面这样

class PromotionDecorator extends Printer {
  printer: Printer;
  constructor(printer: Printer){
    super()
    this.printer = printer
  }

  print(): string {
    return `${this.printer.print()} (Best sell!)`
  }
}

之後我们只要传入需要被装饰的实例到装饰器当中,建立新的、被装饰过的实例,执行 print 方法之後,就可以得到我们想要的结果罗!

const magazine = new PromotionDecorator(economyMagazine)
const book = new PromotionDecorator(scienceBook)

magazine.print()   // This is a economy magazine! (Best sell!)
book.print()       // This is a science book! (Best sell!)

优点与缺点

使用装饰器的好处是,可以快速延伸原有物件的功能,而且不用建立任何新的物件。而多个装饰器可以层层嵌套,因此可以快速建立多样化的功能。

但反过来说,在层层嵌套的情况下,一旦中间其中一个装饰器需要变更行为或移除,就会造成一些麻烦。


<<:  [Day 25]从零开始学习 JS 的连续-30 Days---addEventListener 事件监听

>>:  26 可以按按钮出牌才算出牌

EP 16: The MenuItem of ListView binds Command in ViewModel - Way 1

Hello, 各位 iT邦帮忙 的粉丝们大家好~~~ 本篇是 Re: 从零开始用 Xamarin 技...

【Day 08】工厂方法设计模式(Python)

前言 上一篇我们讨论DDD的战术设计,它建议引用各种设计模式,提高生产力,因此接下来,就来介绍各种设...

【没钱买ps,PyQt自己写】Day 18 / Project 使用 QTimer,自制码表(计时器) PyQt5 stopwatch DIY

看完这篇文章你会得到的成果图 前言 这篇我们要来学一个新的东西 QTimer! QTimer 是独立...

Day1对於学习Java的看法&安装程序

刚读大一的时候,最让我感到头痛的就是程序设计课了!因为我一直以来都不怎麽喜欢电脑相关的东西,更别说是...

自动化测试,让你上班拥有一杯咖啡的时间 | Day 8 - 用 beforeEach 归纳重复行为

此系列文章会同步发文到个人部落格,有兴趣的读者可以前往观看喔。 当测试脚本有重复的地方,除了可以写...