開局一張圖,剩下全靠寫...
設計模式文章集合:http://aphysia.cn/categories/designpattern

接觸過 <code>Spring</code> 或者 <code>Springboot</code> 的同學或許都了解, <code>Bean</code> 預設是單例的,也就是全局共用同一個對象,不會因為請求不同,使用不同的對象,這裡我們不會讨論單例,前面已經讨論過單例模式的好處以及各種實作,有興趣可以了解一下:http://aphysia.cn/archives/designpattern1。除了單例以外,<code>Spring</code>還可以設定其他的作用域,也就是<code>scope="prototype"</code>,這就是原型模式,每次來一個請求,都會新建立一個對象,這個對象就是按照原型執行個體建立的。
原型模式,也是建立型模式的一種,是指用原型執行個體指定建立對象的種類,并且通過拷貝這些原型建立新的對象,簡單來說,就是拷貝。一般适用于:
執行個體比較複雜,完全建立成本高,直接複制比較簡單
構造函數比較複雜,建立可能産生很多不必要的對象
優點:
隐藏了建立執行個體的具體細節
建立對象效率比較高
如果一個對象大量相同的屬性,隻有少量需要特殊化的時候,可以直接用原型模式拷貝的對象,加以修改,就可以達到目的。
一般來說,原型模式就是用來複制對象的,那麼複制對象必須有原型類,也就是<code>Prototype</code>,<code>Prototype</code>需要實作<code>Cloneable</code>接口,實作這個接口才能被拷貝,再重寫<code>clone()</code>方法,還可以根據不同的類型來快速擷取原型對象。
我們先定義一個原型類<code>Fruit</code>:
以及拓展了<code>Fruit</code>類的實體類<code>Apple</code>,<code>Pear</code>,<code>Watermelon</code>:
建立一個擷取不同水果類的緩存類,每次取的時候,根據不同的類型,取出來,拷貝一次傳回即可:
測試一下,分别擷取不同的水果,以及對比兩次擷取同一種類型,可以發現,兩次擷取的同一種類型,不是同一個對象:
結果如下:
再測試一下,我們看看裡面的<code>name</code>屬性是不是同一個對象:
結果如下,裡面的字元串确實還是用的是同一個對象:
這是為什麼呢?因為上面使用的clone()是淺拷貝!!!不過有一點,字元串在Java裡面是不可變的,如果發生修改,也不會修改原來的字元串,由于這個屬性的存在,類似于深拷貝。如果屬性是其他自定義對象,那就得注意了,淺拷貝不會真的拷貝該對象,隻會拷貝一份引用。
這裡不得不介紹一下淺拷貝與深拷貝的差別:
淺拷貝:沒有真正的拷貝資料,隻是拷貝了一個指向資料記憶體位址的指針
深拷貝:不僅建立了指針,還拷貝了一份資料記憶體
如果我們使用<code>Fruit apple = apple1</code>,這樣隻是拷貝了對象的引用,其實本質上還是同一個對象,上面的情況雖然對象是不同的,但是<code>Apple</code>屬性的拷貝還屬于同一個引用,位址還是一樣的,它們共享了原來的屬性對象<code>name</code>。
那如何進行深拷貝呢?一般有以下方案:
直接 new 對象,這個不用考慮了
序列化與反序列化:先序列化之後,再反序列化回來,就可以得到一個新的對象,注意必須實作<code>Serializable</code>接口。
自己重寫對象的<code>clone()</code>方法
序列化實作代碼如下:
建立一個<code>Student</code>類和<code>School</code>類:
序列化拷貝的類:
測試類:
上面的結果均是<code>false</code>,說明确實不是同一個對象,發生了深拷貝。
前面的<code>Student</code>和<code>School</code>都實作<code>Cloneable</code>接口,然後重寫<code>clone()</code>方法:
測試結果一樣,同樣都是<code>false</code>,也是發生了深拷貝。
原型模式适用于建立對象需要很多步驟或者資源的場景,而不同的對象之間,隻有一部分屬性是需要定制化的,其他都是相同的,一般來說,原型模式不會單獨存在,會和其他的模式一起使用。值得注意的是,拷貝分為淺拷貝和深拷貝,淺拷貝如果發生資料修改,不同對象的資料都會被修改,因為他們共享了中繼資料。
【作者簡介】:
秦懷,公衆号【秦懷雜貨店】作者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。個人寫作方向:<code>Java源碼解析</code>,<code>JDBC</code>,<code>Mybatis</code>,<code>Spring</code>,<code>redis</code>,<code>分布式</code>,<code>劍指Offer</code>,<code>LeetCode</code>等,認真寫好每一篇文章,不喜歡标題黨,不喜歡花裡胡哨,大多寫系列文章,不能保證我寫的都完全正确,但是我保證所寫的均經過實踐或者查找資料。遺漏或者錯誤之處,還望指正。
劍指Offer全部題解PDF
2020年我寫了什麼?
開源程式設計筆記
關注公衆号 ”秦懷雜貨店“ 可以領取<code>劍指 Offer V1</code>版本的 <code>PDF</code>解法,V2版本增加了題目,還在哼哧哼哧的更新中,并且為每道題目增加了<code>C++</code>解法,敬請期待。