Go設(shè)計模式之原型模式圖文詳解
原型模式
原型模式是一種創(chuàng)建型設(shè)計模式, 使你能夠復(fù)制已有對象, 而又無需使代碼依賴它們所屬的類。
所有的原型類都必須有一個通用的接口, 使得即使在對象所屬的具體類未知的情況下也能復(fù)制對象。 原型對象可以生成自身的完整副本, 因為相同類的對象可以相互訪問對方的私有成員變量。
問題
如果你有一個對象, 并希望生成與其完全相同的一個復(fù)制品, 你該如何實現(xiàn)呢? 首先, 你必須新建一個屬于相同類的對象。 然后, 你必須遍歷原始對象的所有成員變量, 并將成員變量值復(fù)制到新對象中。
不錯! 但有個小問題。 并非所有對象都能通過這種方式進行復(fù)制, 因為有些對象可能擁有私有成員變量, 它們在對象本身以外是不可見的。
“從外部” 復(fù)制對象并非總是可行。
直接復(fù)制還有另外一個問題。 因為你必須知道對象所屬的類才能創(chuàng)建復(fù)制品, 所以代碼必須依賴該類。 即使你可以接受額外的依賴性, 那還有另外一個問題: 有時你只知道對象所實現(xiàn)的接口, 而不知道其所屬的具體類, 比如可向方法的某個參數(shù)傳入實現(xiàn)了某個接口的任何對象。
解決方案
原型模式將克隆過程委派給被克隆的實際對象。 模式為所有支持克隆的對象聲明了一個通用接口, 該接口讓你能夠克隆對象, 同時又無需將代碼和對象所屬類耦合。 通常情況下, 這樣的接口中僅包含一個 克隆
方法。
所有的類對 克隆
方法的實現(xiàn)都非常相似。 該方法會創(chuàng)建一個當(dāng)前類的對象, 然后將原始對象所有的成員變量值復(fù)制到新建的類中。 你甚至可以復(fù)制私有成員變量, 因為絕大部分編程語言都允許對象訪問其同類對象的私有成員變量。
支持克隆的對象即為原型。 當(dāng)你的對象有幾十個成員變量和幾百種類型時, 對其進行克隆甚至可以代替子類的構(gòu)造。
預(yù)生成原型可以代替子類的構(gòu)造。
其運作方式如下: 創(chuàng)建一系列不同類型的對象并不同的方式對其進行配置。 如果所需對象與預(yù)先配置的對象相同, 那么你只需克隆原型即可, 無需新建一個對象。
真實世界類比
現(xiàn)實生活中, 產(chǎn)品在得到大規(guī)模生產(chǎn)前會使用原型進行各種測試。 但在這種情況下, 原型只是一種被動的工具, 不參與任何真正的生產(chǎn)活動。
一個細胞的分裂。
由于工業(yè)原型并不是真正意義上的自我復(fù)制, 因此細胞有絲分裂 (還記得生物學(xué)知識嗎?) 或許是更恰當(dāng)?shù)念惐取?有絲分裂會產(chǎn)生一對完全相同的細胞。 原始細胞就是一個原型, 它在復(fù)制體的生成過程中起到了推動作用。
原型模式結(jié)構(gòu)
基本實現(xiàn)
- 原型 (Prototype) 接口將對克隆方法進行聲明。 在絕大多數(shù)情況下, 其中只會有一個名為
clone
克隆的方法。 - 具體原型 (Concrete Prototype) 類將實現(xiàn)克隆方法。 除了將原始對象的數(shù)據(jù)復(fù)制到克隆體中之外, 該方法有時還需處理克隆過程中的極端情況, 例如克隆關(guān)聯(lián)對象和梳理遞歸依賴等等。
- 客戶端 (Client) 可以復(fù)制實現(xiàn)了原型接口的任何對象。
原型注冊表實現(xiàn)
- 原型注冊表 (Prototype Registry) 提供了一種訪問常用原型的簡單方法, 其中存儲了一系列可供隨時復(fù)制的預(yù)生成對象。 最簡單的注冊表原型是一個
名稱 → 原型
的哈希表。 但如果需要使用名稱以外的條件進行搜索, 你可以創(chuàng)建更加完善的注冊表版本。
偽代碼
在本例中, 原型模式能讓你生成完全相同的幾何對象副本, 同時無需代碼與對象所屬類耦合。
克隆一系列位于同一類層次結(jié)構(gòu)中的對象。
所有形狀類都遵循同一個提供克隆方法的接口。 在復(fù)制自身成員變量值到結(jié)果對象前, 子類可調(diào)用其父類的克隆方法。
原型模式適合應(yīng)用場景
如果你需要復(fù)制一些對象, 同時又希望代碼獨立于這些對象所屬的具體類, 可以使用原型模式。
這一點考量通常出現(xiàn)在代碼需要處理第三方代碼通過接口傳遞過來的對象時。 即使不考慮代碼耦合的情況, 你的代碼也不能依賴這些對象所屬的具體類, 因為你不知道它們的具體信息。
原型模式為客戶端代碼提供一個通用接口, 客戶端代碼可通過這一接口與所有實現(xiàn)了克隆的對象進行交互, 它也使得客戶端代碼與其所克隆的對象具體類獨立開來。
如果子類的區(qū)別僅在于其對象的初始化方式, 那么你可以使用該模式來減少子類的數(shù)量。 別人創(chuàng)建這些子類的目的可能是為了創(chuàng)建特定類型的對象。
在原型模式中, 你可以使用一系列預(yù)生成的、 各種類型的對象作為原型。
客戶端不必根據(jù)需求對子類進行實例化, 只需找到合適的原型并對其進行克隆即可。
實現(xiàn)方式
創(chuàng)建原型接口, 并在其中聲明
克隆
方法。 如果你已有類層次結(jié)構(gòu), 則只需在其所有類中添加該方法即可。原型類必須另行定義一個以該類對象為參數(shù)的構(gòu)造函數(shù)。 構(gòu)造函數(shù)必須復(fù)制參數(shù)對象中的所有成員變量值到新建實體中。 如果你需要修改子類, 則必須調(diào)用父類構(gòu)造函數(shù), 讓父類復(fù)制其私有成員變量值。
如果編程語言不支持方法重載, 那么你可能需要定義一個特殊方法來復(fù)制對象數(shù)據(jù)。 在構(gòu)造函數(shù)中進行此類處理比較方便, 因為它在調(diào)用
new
運算符后會馬上返回結(jié)果對象。克隆方法通常只有一行代碼: 使用
new
運算符調(diào)用原型版本的構(gòu)造函數(shù)。 注意, 每個類都必須顯式重寫克隆方法并使用自身類名調(diào)用new
運算符。 否則, 克隆方法可能會生成父類的對象。你還可以創(chuàng)建一個中心化原型注冊表, 用于存儲常用原型。
你可以新建一個工廠類來實現(xiàn)注冊表, 或者在原型基類中添加一個獲取原型的靜態(tài)方法。 該方法必須能夠根據(jù)客戶端代碼設(shè)定的條件進行搜索。 搜索條件可以是簡單的字符串, 或者是一組復(fù)雜的搜索參數(shù)。 找到合適的原型后, 注冊表應(yīng)對原型進行克隆, 并將復(fù)制生成的對象返回給客戶端。
最后還要將對子類構(gòu)造函數(shù)的直接調(diào)用替換為對原型注冊表工廠方法的調(diào)用。
原型模式優(yōu)缺點
你可以克隆對象, 而無需與它們所屬的具體類相耦合。
你可以克隆預(yù)生成原型, 避免反復(fù)運行初始化代碼。
你可以更方便地生成復(fù)雜對象。
你可以用繼承以外的方式來處理復(fù)雜對象的不同配置。
克隆包含循環(huán)引用的復(fù)雜對象可能會非常麻煩。
代碼示例
Go設(shè)計模式之原型模式講解和代碼示例_Golang_腳本之家 (jb51.net)
以上就是Go設(shè)計模式之原型模式圖文詳解的詳細內(nèi)容,更多關(guān)于Go原型模式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
GO語言入門學(xué)習(xí)之基本數(shù)據(jù)類型字符串
字符串在Go語言中以原生數(shù)據(jù)類型出現(xiàn),使用字符串就像使用其他原生數(shù)據(jù)類型(int、bool、float32、float64 等)一樣,下面這篇文章主要給大家介紹了關(guān)于GO語言入門學(xué)習(xí)之基本數(shù)據(jù)類型字符串的相關(guān)資料,需要的朋友可以參考下2022-04-04Go語言開發(fā)kube-scheduler整體架構(gòu)深度剖析
這篇文章主要為大家介紹了Go語言開發(fā)kube-scheduler整體架構(gòu)深度剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04