如果物件的建立成本比較大,而同乙個類的不同物件之間差別不大(大部分欄位都相同),在這種情況下,我們可以利用對已有物件(原型)進行複製(或者叫拷貝、轉殖)的方式,來建立新物件,以達到節省建立時間的目的。這種基於原型來建立物件的方式就叫作原型設計模式,簡稱原型模式。
核心:拷貝(轉殖)
建立物件包含的申請記憶體、給成員變數賦值這一過程,本身並不會花費太多時間,對於大部分業務系統來說,這點時間完全是可以忽略的。
但是,如果物件中的資料需要經過複雜的計算才能得到(比如排序、計算雜湊值),或者需要從 rpc、網路、資料庫、檔案系統等非常慢速的 io 中讀取,這種情況下,我們就可以利用原型模式,從其他已有物件中直接拷貝得到,而不用每次在建立新物件的時候,都重複執行這些耗時的操作。
通過個人資訊類(information)建立兩個例項物件(zs、lf)。
抽象原型類如下:
class
information
:"""個人資訊"""
def__init__
(self)
: self.name =
none
self.age =
none
self.height =
none
self.hobbies =
list()
defrun
(self)
:"""自我介紹方法"""
print
("我叫{}: 年齡:{} 身高:{} 愛好: {}"
.format
(self.name, self.age, self.height, self.hobbies)
)
具體原型類如下:
class
prototype
:def
__init__
(self, obj)
: self.copy_object = obj(
)def
clone
(self,
**attr)
:'''轉殖物件'''
obj = copy.deepcopy(self.copy_object)
# 深轉殖
obj.__dict__.update(attr)
return obj
客戶類
if __name__ ==
'__main__'
: people = prototype(information)
# 例項化乙個具體原型
zs = people.clone(name=
'張山'
, age=
"30"
, height=
'170cm'
, hobbies=
['**'
,'讀書'])
zs.run(
) lf = people.clone(name=
'李飛'
, age=
"20"
, height=
'190cm'
, hobbies=
['籃球'
,'羽毛球'])
lf.run(
)
輸出結果:
我叫張山: 年齡:30 身高:170cm 愛好:
['**'
,'讀書'
]我叫李飛: 年齡:20 身高:190cm 愛好:
['籃球'
,'羽毛球'
]
也可以換一種寫法,寫成如下形式:
import copy
class
information
:"""個人資訊"""
def__init__
(self)
: self.name =
none
self.age =
none
self.height =
none
self.hobbies =
list()
defrun
(self)
:"""自我介紹方法"""
print
("我叫{}: 年齡:{} 身高:{} 愛好: {}"
.format
(self.name, self.age, self.height, self.hobbies)
)if __name__ ==
'__main__'
: zs = copy.deepcopy(information())
zs.name =
'張三'
zs.age =
"30"
zs.height =
'170cm'
zs.hobbies =
['**'
,'讀書'
] zs.run(
) lf = copy.copy(information())
lf.name =
'李飛'
lf.age =
'20'
lf.height =
'190cm'
lf.hobbies =
['籃球'
,'羽毛球'
] lf.run(
)
上面例子中使用的是深轉殖(深拷貝)。其實還有淺轉殖(淺拷貝)。
淺轉殖(淺拷貝):
深轉殖(深拷貝):
淺轉殖可能出現以下問題。舉例
>>
>
import copy
>>
> a =[1
,"2",[
'a',
none]]
>>
> b = copy.copy(a)
# 淺轉殖
>>
> b[1
,'2',[
'a',
none]]
>>
> c = copy.deepcopy(a)
# 深轉殖
>>
> c[1
,'2',[
'a',
none
]]
b淺轉殖a,c深轉殖a。
如果a修改了列表中巢狀的子列表中的內容,則b也會跟著變動,而深轉殖的c卻不會發生變化。
>>
> a[2]
1)# >>
> a[1
,'2',[
'a',
none,1
]]>>
> b # 可以看出,b也被修改了[1
,'2',[
'a',
none,1
]]>>
> c[1
,'2',[
'a',
none
]]
這是因為b
只是轉殖了a[2]
指向的記憶體位址,而**a[2]
是乙個列表,列表屬於可變型別**,因此,當a[2]
發生變化時,b
也跟著變動。這就是淺轉殖的***;而c
直接完全轉殖了a
中的值,並不會因為a
發生變化而變化。
所以,一般建議使用深轉殖。
大話設計模式 原型模式
學無止境,精益求精 十年河東,十年河西,莫欺少年窮 學歷代表你的過去,能力代表你的現在,學習代表你的將來 上篇部落格介紹了c 深淺複製,其實原型模式講的主要就是物件的深淺複製 參考 c 深淺複製 memberwiseclone ok,言歸正傳 原型模式的概念 用原型例項指定建立物件的種類,並且通過拷...
《大話設計模式 原型模式》筆記
1 原型模式 prototype 用原型例項指定建立物件的種類,並通過拷貝這些原型建立新的物件。2 原型模式結構圖 3 簡單 實現 3.1 繼承cloneable介面 public class concrereprototype implements cloneable public string ...
大話設計模式 原型模式 9
using system using system.collections.generic using system.linq using system.text namespace prototypefactory public prototype string id public abstrac...