Design Pattern (9) - Prototype Pattern (原型模式)

您可於此 design_pattern repo 下載 Design Pattern 系列程式碼。

前言

這次的 Pattern 讓我想到以前做過的一個 App,但當時還沒有學習到 Pattern,所以沒有用 Pattern 來處理,現在發現這個功能很適合套用 prototype pattern

這是一個用來編輯音樂燈光秀的 App,有興趣的讀者可以下載玩玩看 🙂

需求

今天收到了客人的需求,客人反應編輯完一條燈光還要編輯另外六條好浪費時間,能不能新增 Copy & Paste 的功能,加快編輯以節省時間,如下圖

物件導向分析 (OOA)

理解需求後,讓我們來快速實作物件導向分析吧!

當我們需要複製 LightShowData 時,只需要同樣的 jsonObject 資料重新 new 一個 LightShowData 即可複製一份

察覺 Forces

來看看上面這樣的設計會有哪些問題

  1. 如果我們的 constructor 很複雜,參數非常多,那麼重新 new 一個實體會需要知道很多細節。
  2. 如果 constructor 創建實體的過程,是很耗時複雜的計算,重新 new 一個實體會讓創建過程效率變差。

套用 Prototype Pattern ( Solution ) 得到新的 Context ( Resulting Context )

做完 OOA,察覺 Forces,看清楚整個 Context 後,就可以來套用 Prototype Pattern 解決這個問題

先來看一下 Prototype Pattern 的 UML

原型模式主要包含以下兩個角色:

  1. Prototype(原型):這是一個抽象介面,定義了複製自身的方法。在實體實現中,這個介面可以是一個抽象類或者實體類,主要目的是提供一個複製自己的方法。這使得在不需要知道物件實體類別的情況下也能創建物件的副本。

  2. Concrete Prototype(實體原型):實現或繼承自原型介面的類。這個類實現了在原型介面中定義的複製(clone)方法,用於創建自身的一個精確副本。在實體實現時,這個類需要提供一個方法來複製自身的屬性,確保新創建的物件與原有物件在狀態上是相同的,但在記憶體中是獨立的。

我們來將 LightShow App 套用 Prototype Pattern

如此我們就得到了一個全新的 Resulting Context

物件導向程式設計 (OOP)

再來我們就可以開始進行物件導向程式開發

[LightShowDataPrototype]

interface LightShowDataPrototype {
    val startIndex: Int
    val lightDataList: List<Int>
    fun clone(): LightShowDataPrototype
}

[LightShowData]

package prototypepattern.source

class LightShowData: LightShowDataPrototype {

    override val startIndex: Int
    override val lightDataList: List<Int>

    constructor(originalDataList: List<Int>) {
        startIndex = originalDataList[0]
        lightDataList = originalDataList.subList(1, originalDataList.size).map { it * 2 }
    }

    constructor(startIndex: Int, lightDataList: List<Int>) {
        this.startIndex = startIndex
        this.lightDataList = lightDataList
    }

    override fun clone(): LightShowDataPrototype {
        return LightShowData(startIndex, lightDataList.toList())
    }
}

[main]

fun main() {
    val originalData = listOf(1, 2, 3, 4, 5)

    // Before using prototype pattern
    val originalLightShowData: LightShowDataPrototype = LightShowData(originalData)
    val newLightShowData: LightShowDataPrototype = LightShowData(originalData)

    println(originalLightShowData)
    println(newLightShowData)

    // After using prototype pattern
    val clonedLightShowData: LightShowDataPrototype = LightShowData(originalData)

    println(originalLightShowData)
    println(clonedLightShowData)
}

我們可以發現,透過 clone() 方法複製,就可以不重複執行下面的程式碼,提升程式碼效能了

originalDataList.subList(1, originalDataList.size).map { it * 2 }



    Enjoy Reading This Article?

    Here are some more articles you might like to read next:

  • 💡 一台電腦操作多個 GitHub 帳號:最簡單快速的 SSH 設定方法
  • 🚀 如何使用 Excalidraw AI 快速生成專業級圖表,提升工作效率!
  • Setup Development Environment on a New macOS
  • Design Pattern (28) - Interpreter Pattern (解譯器模式)
  • Design Pattern (27) - Visitor Pattern (訪問者模式)