第9章:原型模式
原型模式
原型模式(prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式
其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。
Prototype
类
ConcretePrototype1
类
客户端代码
这样可以直接克隆,而不用实例化ConcretePrototype1
。
对于.NET
而言,不需要原型抽象类Prototype
的定义,因为克隆为常用操作,所以.NET
在System
命名空间中提供了ICloneable
接口,其中唯一一个方法就是Clone()
,只需要实现这个接口就可以完成原型模式了。
原型模式示例
任务:简历复制
from typing import Text
from copy import copy, deepcopy
# 简历类
class Resume(object):
def __init__(self, name: Text) -> None:
self.__name = name
self.__age = None
self.__sex = None
self.__time_area = None
self.__company = None
def set_personal_info(self, sex: Text, age: int) -> None:
"""
设置个人信息
"""
self.__age = age
self.__sex = sex
def set_work_experience(self, time_area: Text, company: Text) -> None:
"""
设置工作经历
"""
self.__time_area = time_area
self.__company = company
def display(self) -> None:
"""
显示
"""
print(self.__name, self.__age, self.__sex)
print("工作经历:", self.__time_area, self.__company)
# 客户端代码(直接赋值,即引用)
if __name__ == "__main__":
resume_a = Resume("cai")
resume_a.set_personal_info("male", 25)
resume_a.set_work_experience("1990-2002", "xx")
resume_b = resume_a
resume_b.set_work_experience("1993-2012", "yy")
resume_c = resume_a
resume_c.set_work_experience("1949-2000", "zz")
resume_a.display()
resume_b.display()
resume_c.display()
cai 25 male
工作经历: 1949-2000 zz
cai 25 male
工作经历: 1949-2000 zz
cai 25 male
工作经历: 1949-2000 zz
# 客户端代码(浅复制)
if __name__ == "__main__":
resume_a = Resume("cai")
resume_a.set_personal_info("male", 25)
resume_a.set_work_experience("1990-2002", "xx")
resume_b = copy(resume_a)
resume_b.set_work_experience("1993-2012", "yy")
resume_c = copy(resume_a)
resume_c.set_work_experience("1949-2000", "zz")
resume_a.display()
resume_b.display()
resume_c.display()
cai 25 male
工作经历: 1990-2002 xx
cai 25 male
工作经历: 1993-2012 yy
cai 25 male
工作经历: 1949-2000 zz
一般在初始化的信息不发生变化的情况下,克隆是最好的方法,不用重新初始化对象,而是动态地获得对象运行时的状态。这既隐藏了对象创建的细节,又能极大提高性能(如果构造函数极其耗时)
浅复制与深复制
MemberwiseClone()
方法:如果字段是值类型的,则对该字段执行逐位复制;如果字段是引用类型,则复制引用但不复制引用的对象。因此,原始对象及其复本引用同一对象。
浅复制
:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深复制
:把要复制的对象所引用的对象都复制一遍,把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
浅复制与深复制示例
任务:简历复制
浅复制
from abc import ABC, abstractmethod
# 复制接口
class ICloneable(ABC):
@abstractmethod
def clone(self) -> object:
pass
# 工作经历类
class WorkExperience(object):
def __init__(self) -> None:
self.__work_date = None
self.__company = None
@property
def work_date(self) -> Text:
return self.__work_date
@work_date.setter
def work_date(self, work_date: Text) -> None:
self.__work_date = work_date
@property
def company(self) -> Text:
return self.__company
@company.setter
def company(self, company: Text) -> None:
self.__company = company
# 简历类
class Resume(ICloneable):
def __init__(self, name: Text) -> None:
self.__name = name
self.__age = None
self.__sex = None
self.__work = WorkExperience()
def set_personal_info(self, sex: Text, age: int) -> None:
"""
设置个人信息
"""
self.__age = age
self.__sex = sex
def set_work_experience(self, time_area: Text, company: Text) -> None:
"""
设置工作经历
"""
self.__work.work_date = time_area
self.__work.company = company
def clone(self) -> Resume:
return copy(self)
def display(self) -> None:
"""
显示
"""
print(self.__name, self.__age, self.__sex)
print("工作经历:", self.__work.work_date, self.__work.company)
# 客户端代码(浅复制)
if __name__ == "__main__":
resume_a = Resume("cai")
resume_a.set_personal_info("male", 25)
resume_a.set_work_experience("1990-2002", "xx")
resume_b = resume_a.clone()
resume_b.set_work_experience("1993-2012", "yy")
resume_c = resume_a.clone()
resume_c.set_work_experience("1949-2000", "zz")
resume_a.display()
resume_b.display()
resume_c.display()
cai 25 male
工作经历: 1949-2000 zz
cai 25 male
工作经历: 1949-2000 zz
cai 25 male
工作经历: 1949-2000 zz
深复制
# 工作经历类
class WorkExperience(ICloneable):
def __init__(self) -> None:
self.__work_date = None
self.__company = None
def clone(self) -> object:
return copy(self)
@property
def work_date(self) -> Text:
return self.__work_date
@work_date.setter
def work_date(self, work_date: Text) -> None:
self.__work_date = work_date
@property
def company(self) -> Text:
return self.__company
@company.setter
def company(self, company: Text) -> None:
self.__company = company
# 简历类
class Resume(ICloneable):
def __init__(self, name: Text=None) -> None:
self.__name = name
self.__age = None
self.__sex = None
self.__work = WorkExperience()
def set_personal_info(self, sex: Text, age: int) -> None:
"""
设置个人信息
"""
self.__age = age
self.__sex = sex
def set_work_experience(self, time_area: Text, company: Text) -> None:
"""
设置工作经历
"""
self.__work.work_date = time_area
self.__work.company = company
def clone(self) -> object:
obj = Resume()
obj.__work = self.__work.clone()
obj.__name = self.__name
obj.__age = self.__age
obj.__sex = self.__sex
return obj
def display(self) -> None:
"""
显示
"""
print(self.__name, self.__age, self.__sex)
print("工作经历:", self.__work.work_date, self.__work.company)
# 客户端代码(深复制)
if __name__ == "__main__":
resume_a = Resume("cai")
resume_a.set_personal_info("male", 25)
resume_a.set_work_experience("1990-2002", "xx")
resume_b = resume_a.clone()
resume_b.set_work_experience("1993-2012", "yy")
resume_c = resume_a.clone()
resume_c.set_work_experience("1949-2000", "zz")
resume_a.display()
resume_b.display()
resume_c.display()
cai 25 male
工作经历: 1990-2002 xx
cai 25 male
工作经历: 1993-2012 yy
cai 25 male
工作经历: 1949-2000 zz