原型模式的使用场景
在创建一个实例,较复杂的或耗时的情况下,复制一个已经存在的实例能使程序运行更高效。
- 类初始化需要耗费很多资源,通过原型拷贝避免这些耗费
- 通过
new
产生一个对象,需要频繁的数据准备或访问权限时 - 保护性拷贝,防止一个对象被调用者修改
原型模式的类图
@startuml
interface Prototype {
+ clone()
}
class ConcretePrototype implements Prototype{
+ clone()
}
class Client
Client .o Prototype
@enduml
- Client: 客户端
- Prototype: 抽象类或接口,声明具有
clone
能力 - ConcretePrototype: 具体的原型类
简单实现
使用原型模式,实现一个文档拷贝的例子. WordDocument
表示一份用户的文档,这个文档中包含文字和图片。
用户希望编辑一份已经存在的文档,但是不确定是否采用新的编辑。因此,为了安全,将原有的文档拷贝一份,在拷贝的文档上进行操作。
原始文档就是样板实例,既原型。
|
|
修改文档文本内容
|
|
输出:
doc1: doc: document text
images: [image1, image2]
doc2: doc: document text
images: [image1, image2]
doc2: doc: update document text
images: [image1, image2]
doc1: doc: document text
images: [image1, image2]
可见新的文档对象的文本内容修改不会影响原始的文本对象。
修改文档文本和图片内容
|
|
输出:
doc1: doc: document text
images: [image1, image2]
doc2: doc: document text
images: [image1, image2]
doc2: doc: update document text
images: [image1, image2, image3]
doc1: doc: document text
images: [image1, image2, image3]
在新文档对象中增加的图片同时也出现在了原始对象中,这是由于 WordDocument
中 clone
的实现是浅拷贝造成的。由于 images
是 List
类型,属于引用类型,浅拷贝传递的是对象的引用。
深拷贝,浅拷贝
对于引用类型对象,变量持有的是对象的引用,在进行拷贝时,如果只是引用赋值,就是浅拷贝,新对象中的变量就还是引用的原型对象中的变量。既 doc2.images
与 doc1.images
都引用的同一个对象。
修改 WordDocument
的 clone
为深拷贝:
|
|
通过深拷贝可以避免对拷贝对象的修改影响原型对象的内容。