1.初識原型模式
用原型實例指定創建對象的種類,并通過拷貝這些原型創建新的對象。
- Prototype:
聲明一個克隆自身的接口,用來約束想要克隆自己的類,要求它們都要實現這里定義的克隆方法。 - ConcretePrototype:
實現Prototype接口的類,這些類真正實現克隆自身的功能。 - Client:
使用原型的客戶端,首先要獲取到原型實例對象,然后通過原型實例克隆自身來創建新的對象實例。
2.體會原型模式
2.1 場景問題——訂單處理系統
現在有一個訂單處理的系統,里面有個保存訂單的業務功能,在這個業務功能里面,客戶有這么一個需求:每當訂單的預定產品數量超過1000的時候,就需要把訂單拆成兩份訂單來保存,如果拆成兩份訂單后,還是超過1000,那就繼續拆分,直到每份訂單的預定產品數量不超過1000。至于為什么要拆分,原因是好進行訂單的后續處理,后續是由人工來處理,每個人工工作小組的處理能力上限是1000。
根據業務,目前的訂單類型被分成兩種:一種是個人訂單,一種是公司訂單。現在想要實現一個通用的訂單處理系統,也就是說,不管具體是什么類型的訂單,都要能夠正常的處理。
該怎么實現呢?
2.2 不用模式的解決方案
存在的問題:
仔細想想,真的沒有關心訂單的類型和具體實現嗎?答案是“否定的”。
事實上在實現訂單處理的時候,上面的實現是按照訂單的類型和具體實現來處理的,就是instanceof的那一段。有朋友可能會問,這樣實現有何不可嗎?
這樣的實現有如下幾個問題:
- 1)既然想要實現通用的訂單處理,那么對于訂單處理的實現對象,是不應該知道訂單的具體實現的,更不應該依賴訂單的具體實現。但是上面的實現中,很明顯訂單處理的對象依賴了訂單的具體實現對象。
- 2)這種實現方式另外一個問題就是:難以擴展新的訂單類型。假如現在要加入一個大客戶專用訂單的類型,那么就需要修改訂單處理的對象,要在里面添加對新的訂單類型的支持,這算哪門子的通用處理。
因此,上面的實現是不太好的,把上面的問題再抽象描述一下:已經有了
某個對象實例后,如何能夠快速簡單地創建出更多的這種對象?
2.3 使用模式的解決方案
3.理解原型模式
3.1 認識原型模式
3.1.1 原型模式的功能
原型模式的功能實際上包含兩個方面:
- 1)一個是通過克隆來創建新的對象實例
- 2)另一個是為克隆出來的新的對象實例復制原型實例屬性的值
原型模式要實現的主要功能就是:通過克隆來創建新的對象實例。
一般來講,新創建出來的實例的數據是和原型實例一樣的。但是具體如何實現克隆,需要由程序自行實現,原型模式并沒有統一的要求和實現算法。
3.1.2 原型與new
原型模式從某種意義上說,就像是new操作,在前面的例子實現中,克隆方法就是使用new來實現的,但請注意,只是“類似于new”而不是“就是new”。
克隆方法和new操作最明顯的不同就在于:new一個對象實例,一般屬性是沒有值的,或者是只有默認值;如果是克隆得到的一個實例,通常屬性是有值的,屬性的值就是原型對象實例在克隆的時候,原型對象實例的屬性的值。
3.1.3 原型實例和克隆的實例
原型實例和克隆出來的實例,本質上是不同的實例,克隆完成后,它們之間是沒有關聯的,如果克隆完成后,克隆出來的實例的屬性的值發生了改變,是不會影響到原型實例的。
3.1.4 原型模式的調用順序示意圖
3.2 Java中的克隆方法
在Java語言中已經提供了clone方法,定義在Object類中。需要克隆功能的類,只需要實現java.lang.Cloneable接口,這個接口沒有需要實現的方法,是一個標識接口。
3.3 淺度克隆和深度克隆
什么是淺度克隆?什么是深度克隆呢?簡單地解釋一下:
- 1)淺度克隆:只負責克隆按值傳遞的數據(比如:基本數據類型、String類型)
- 2)深度克隆:除了淺度克隆要克隆的值外,還負責克隆引用類型的數據,基本上就是被克隆實例所有的屬性的數據都會被克隆出來。
深度克隆還有一個特點,如果被克隆的對象里面的屬性數據是引用類型,也就是屬性的類型也是對象,那么需要一直遞歸的克隆下去。這也意味著,要想深度克隆成功,必須要整個克隆所涉及的對象都要正確實現克隆方法,如果其中有一個沒有正確實現克隆,那么就會導致克隆失敗。
3.4 原型管理器
如果一個系統中原型的數目不固定,比如系統中的原型可以被動態的創建和銷毀,那么就需要在系統中維護一個當前可用的原型的注冊表,這個注冊表就被稱為原型管理器。
其實如果把原型當成一個資源的話,原型管理器就相當于一個資源管理器,在系統開始運行的時候初始化,然后運行期間可以動態的添加資源和銷毀資源。從這個角度看,原型管理器就可以相當于一個緩存資源的實現,只不過里面緩存和管理的是原型實例而已。
有了原型管理器過后,一般情況下,除了向原型管理器里面添加原型對象的時候是通過new來創造的對象,其余時候都是通過向原型管理器來請求原型實例,然后通過克隆方法來獲取新的對象實例,這就可以實現動態管理、或者動態切換具體的實現對象實例。
3.5 原型模式的優缺點
- 對客戶端隱藏具體的實現類型
- 在運行時動態改變具體的實現類型
- 深度克隆方法實現會比較困難
4.思考原型模式
4.1 原型模式的本質
原型模式的本質是:克隆生成對象。
4.2 何時選用
如果一個系統想要獨立于它想要使用的對象時,可以使用原型模式,讓系統只面向接口編程,在系統需要新的對象的時候,可以通過克隆原型來得到
如果需要實例化的類是在運行時刻動態指定時,可以使用原型模式,通過克隆原型來得到需要的實例