原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新对象。
原型模式 Prototype
所谓原型模式 Prototype['protəˌtaɪp]
,就是指 clone
技术,以某个对象为原型,复制出一个新的对象。
类图结构
结构解析
Prototype
抽象类,原型类申明一个clone
自身的接口。ConcretePrototype
实现类,实现一个克隆自身的操作。client
客户端持有原型类实例。
Java
中的原型模式
Cloneable
接口
在 Java
中,原型模式的 Prototype
抽象类并不需要我们定义,Cloneable
接口实现了这个功能。先看看这个接口的定义:
1 | /** |
源码中 Cloneable
是一个空接口,仅用来标记对象,并没有定义 clone
方法。但是 Java
中所有对象都继承了 Object
类,而 clone()
正是它的标准方法之一。
1 | public class Object { |
- 实现
Cloneable
接口
从源码中可以看出,如果要使用Object.clone
则必须实现Cloneable
接口,否则会抛出CloneNotSupportedException
异常。 clone
新对象时不会调用构造函数clone
方法最终调用了native
的internalClone
方法,而这个方法是直接从堆内存中以二进制流拷贝的,所以产生新对象时并不会调用类的构造方法。
深/浅拷贝
深/浅拷贝主要区别在对类中引用对象的处理:
- 浅拷贝
shallow copy
浅拷贝在拷贝对象时,并不会拷贝对象里的引用对象,也就是说不拷贝该对象的属性。 - 深拷贝
deep copy
深拷贝在拷贝对象时,需要手动代码实现对引用对象的拷贝,也就是把该对象的所有属性也克隆出一份新的。
示例
1 | // 1. Prototype |
在测试用例中,修改 TestObject
对象的值后,两种拷贝表现出来的结果不一样:
- 浅拷贝
因为引用对象并没有克隆,指向的是同一个地址空间,所以TestObject
对象修改后,浅拷贝生成的新对象会跟着变化。 - 深拷贝
深拷贝克隆了所有的引用对象,也就是在新地址中拷贝了引用对象的值,源TestObject
对象的修改不会对深拷贝产生影响。
总结
原型模式适合在什么场景使用?
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等
- 初始化时需要非常繁琐的数据准备或访问权限,则可以使用原型模式
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用
在实际项目中,原型模式通常和工厂方法模式一起出现,通过 clone
的方法创建一个对象,然后由工厂方法提供给调用者。
参考文档
- 大话设计模式
Android
源码设计模式解析与实战- 原型模式(深/浅拷贝)
- 原型模式详解
- 原型模式
- 原型模式介绍