iT邦幫忙

2021 iThome 鐵人賽

DAY 21
0

今天來介紹 Creational Patterns 當中的最後一個模式。

假設這裡有一個 Engineer 類別,他除了有個 name 屬性之外,還擁有 toolBox,可以不斷加入新的工具,成為超級工具人。EngineerToolBox 的細節如下:

class Engineer {
  name: string
  toolBox: ToolBox

  constructor(name: string) {
    this.name = name
    this.toolBox = new ToolBox()
  }
}

class ToolBox {
  tools: string[]

  constructor(){
    this.tools = []
  }

  addTools(tools: string[]) {
    this.tools.push(...tools)
  }
}

接著,我們就可以產生出一個 Engineer 實例如下

const a = new Engineer('foo')
a.toolBox.addTools(['a', 'b', 'c', 'd', 'e'])

a.name                    // 'foo'
a.toolBox.tools           // ['a', 'b', 'c', 'd', 'e']

但這時候,如果有另外一位使用者,也想要擁有一個跟 a 一樣的Engineer,有一樣的名字,和一樣的 tools,於是就用同樣的方式:先建立Engineer 實例,然後再加入 tools

const b = new Engineer('foo')
b.toolBox.addTools(['a', 'b', 'c', 'd', 'e'])

b.name                    // 'foo'
b.toolBox.tools           // ['a', 'b', 'c', 'd', 'e']

就大功告成了!

問題

今天要建立一個 b 看起來很簡單,但如果 a 本身是一個很複雜的物件,或者當中屬性的資料需要經過複雜的操作或運算才能獲得,那麼要建立一個跟 a 一模一樣的 b,就會變得非常麻煩。

那麼,有沒有一個可以讓我們直接複製 a 的方式呢?

實作方式

為了讓我們可以快速地複製 Engineer 的實例,我們在 Engineer 當中加入了 clone 的方法。另一方面,也需要為 ToolBox 製作 clone 方法。細節如下:

class Engineer {
  name: string
  toolBox: ToolBox

  constructor(name: string) {
    this.name = name
    this.toolBox = new ToolBox()
  }

  clone(): this {
    const clone = Object.create(this)
    clone.toolBox = this.toolBox.clone()

    return clone
  }
}

class ToolBox {
  tools: string[]

  constructor(){
    this.tools = []
  }

  addTools(tools: string[]) {
    this.tools.push(...tools)
  }

  clone(): ToolBox {
    const clone = new ToolBox()
    clone.addTools(this.tools)
    return clone
  }
}

接著,再讓我們重新建立一次 a

const a = new Engineer('foo')
a.toolBox.addTools(['a', 'b', 'c', 'd', 'e'])

然後,我們用 clone 方法來複製 a,立即得到一個跟 a 一模一樣的 b

const b = a.clone()

b.name                    // 'foo'
b.toolBox.tools           // ['a', 'b', 'c', 'd', 'e']

雖然複製出來的時候是一模一樣,但實際上是兩個不同的、獨立的個體,所以我們可以分別為他們加入新的 tool,得到不同的結果

a.toolBox.addTools(['f'])
b.toolBox.addTools(['g'])

a.toolBox.tools            // ['a', 'b', 'c', 'd', 'e', 'f']
b.toolBox.tools            // ['a', 'b', 'c', 'd', 'e', 'g']

原型模式

透過原型模式,讓我們能夠快速複製出同樣的物件,好處是我們透過複製,我們不需要再次經歷過該物件被建立的過程。

不過複製本身也帶有一些挑戰,如果一個物件裡面引用/指向了許多其他的物件,那麼我們就不能單純這些物件的複製 "reference" (shallow copy),而是要建立出獨立物件們 (deep copy)。所以越複雜的物件,要複製它就可能有更多的挑戰!


上一篇
Builder 建造者模式
下一篇
Adaptor 轉接器模式
系列文
幫自己搞懂物件導向和設計模式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言