程式設計旅途是漫長遙遠的,在不同時刻有不同的感悟,本文會一直更新下去。
思考總結
思考問題
如果沒有原型模式,當我們複製複雜物件,在新建相同類的物件,遍歷原始物件中的所有成員變數並將成員變數複製到新物件的過程中會產生什麼問題?
什麼是原型模式
原型是一種建立型設計模式,使你能夠複製已有物件,而又無需使程式碼依賴它們所屬的類。
原型模式:用原型範例指定建立物件的種類,並且通過拷貝這些原型建立新的物件。
含義:
- 原型模式將克隆過程委派給被克隆的實際物件。模式為所有支援克隆的物件宣告了一個通用介面,該介面讓你能夠克隆物件,同時又無需將程式碼和物件所屬類耦合。你甚至可以複製私有成員變數,因為絕大部分程式語言都允許物件存取其自身的私有成員變數。支援克隆的物件即為原型。
何時使用:
- 如果你需要複製一些物件,同時又希望程式碼獨立於這些物件所屬的具體類,可以使用原型模式。通常出現在程式碼需要處理第三方程式碼通過介面傳遞過來的物件時。即使不考慮程式碼耦合的情況,你的程式碼也不能依賴這些物件所屬的具體類,因為你不知道它們的具體 資訊。
- 如果子類的區別僅在於其物件的初始化方式,那麼你可以使用該模式來減少子類的數量。別人建立這些子類的目的可能 是為了建立特定型別的物件。
- 當要範例化的類是在執行時刻指定時,例如,通過動態裝載。
- 當一個類的範例只能有幾個不同狀態組合中的一種時。建立一系列預生成的、各種型別的物件作為原型並克隆它們可能比每次用合適的狀態手工範例化該類更方便一些。
- 當你的物件有幾十個成員變數和幾百種型別時,對其進行克隆甚至可以代替子類的構造。建立一系列不同型別的物件並用不同的方式對其進行設定。如果所需物件與預先設定的物件相同,那麼你只需克隆原型即可,無需新建一個物件。
實現方法:
- 建立原型介面,並在其中宣告克隆方法。如果你已有類層次結構,則只需在其所有類中新增該方法即可。
- 原型類必須另行定義一個以該類物件為引數的建構函式。建構函式必須複製引數物件中的所有成員變數值到新建實體中。 如果你需要修改子類,則必須呼叫父類別建構函式,讓父類別複製其私有成員變數值。
- 每個類都必須顯式重寫克隆方法並使 用自身類名呼叫 new 運運算元。
- 你還可以建立一個中心化原型登入檔,用於儲存常用原型。
- 你可以新建一個工廠類來實現登入檔,或者在原型基礎類別中新增一個獲取原型的靜態方法。該方法必須能夠根據使用者端代 碼設定的條件進行搜尋。搜尋條件可以是簡單的字串,或 者是一組複雜的搜尋引數。找到合適的原型後,登入檔應對原型進行克隆,並將複製生成的物件返回給使用者端。最後還要將對子類建構函式的直接呼叫替換為對原型登入檔工廠方法的呼叫。
應用範例:
優點:
- 你可以克隆物件,而無需與它們所屬的具體類相耦合。
- 你可以克隆預生成原型,避免反覆執行初始化程式碼。效能提高。 逃避建構函式的約束。
- 你可以更方便地生成複雜物件。
- 你可以用繼承以外的方式來處理複雜物件的不同設定。
缺點:
- 克隆包含迴圈參照的複雜物件可能會非常麻煩。
- 必須實現 Cloneable 介面。
使用場景:
- 資源優化場景。 類初始化需要消化非常多的資源,這個資源包括資料、硬體資源等。 效能和安全要求的場景。
- 通過 new 產生一個物件需要非常繁瑣的資料準備或存取許可權,則可以使用原型模式。
- 一個物件多個修改者的場景。 一個物件需要提供給其他物件存取,而且各個呼叫者可能都需要修改其值時,可以考慮使用原型模式拷貝多個物件供呼叫者使用。
- 在實際專案中,原型模式很少單獨出現,一般是和工廠方法模式一起出現,通過 clone 的方法建立一個物件,然後由工廠方法提供給呼叫者。
與其他模式的關係:
- 原型可用於儲存命令的歷史記錄。
- 大量使用組合和裝飾的設計通常可從對於原型的使用中獲益。 你可以通過該模式來複制複雜結構,而非從零開始重新構造。
- 原型並不基於繼承,因此沒有繼承的缺點。另一方面,原型需要對被複制物件進行復雜的初始化。 工廠方法基於繼承, 但是它不需要初始化步驟。
- 有時候原型可以作為備忘錄的一個簡化版本,其條件是你需要在歷史記錄中儲存的物件的狀態比較簡單,不需要連結其 他外部資源,或者連結可以方便地重建。
- 抽象工廠、生成器和原型都可以用單例來實現。
注意事項:原型模式分淺拷貝和深拷貝,在設計原型模式的時候需要著重考慮。
參考資料
- 《Go語言核心程式設計》李文塔
- 《Go語言高階程式設計》柴樹彬、曹春輝
- 《大話設計模式》程傑
- 《深入設計模式》亞歷山大·什韋茨
- 菜鳥教學