- 定义:
- 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
- 说明:
- 通过clone方法来拷贝原对象,值的注意的是,拷贝后的对象与原对象并不是同一个对象,这个可以通过equal方法来验证,这点也可以说是与享元模式的区别吧,在生活中,细胞分裂这个可以说是原型模式的一种具体表现吧,或者复印的卷子等等,clone也分为浅拷贝和深拷贝,kotlin中的Any类中是没有clone方法的,所以这例子都是用java来编写。
- 类图:
- 使用场景(http://www.runoob.com/design-pattern/prototype-pattern.html):
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等(资源优化)。
- 性能和安全要求的场景。
- 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
- 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。在工厂出来的对象可以看成是一样的,
- 浅拷贝和深拷贝:
- 浅拷贝:对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象------>意思就是复制的引用还是直接指向了原来的引用类型的成员变量,所以修改了该引用,还是会影响到原对象
- 浅拷贝适用于 对象只包含原始数据域或者不可变对象域的时候,提高效率
- 深拷贝:对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制
- 引用类型的成员变量继承Cloneable(例如ArrayList),可以在Clone方法中直接让其执行成员变量的clone的方法
- 相反(例如Int[]),则需要使用序列化来实现深拷贝
- 在Java语言里深度克隆一个对象。经常能够先使对象实现Serializable接口,然后把对象(实际上仅仅是对象的拷贝)写到一个流里(序列化),再从流里读回来(反序列化),便能够重建对象。
- 这样做的前提就是对象以及对象内部全部引用到的对象都是可序列化的。否则。就须要细致考察那些不可序列化的对象可否设成transient,从而将之排除在复制过程之外。
- 有一些对象。比方线程(Thread)对象或Socket对象。是不能简单复制或共享的。
- 浅拷贝:对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象------>意思就是复制的引用还是直接指向了原来的引用类型的成员变量,所以修改了该引用,还是会影响到原对象
- 疑问:
- 图解设计模式(菜鸟教程)中的例子不太明白使用原型模式的意义,实例化后放入到map中,取出来的是拷贝后的对象,这样操作的目的是什么
- 注意事项:
- final 类型修饰的成员变量不能进行深拷贝
- 单例模式与原型模式是冲突的
- Object中的clone()方法是线程不同步的.在需要线程安全的场景,需要做好同步工作.
- 原型模式中的 原型 与 clone实例通过 equals 和 ==比较返回值都是 false
- 尽量使用深拷贝类防止错误的发生,对于只有值域类型的对象使用浅拷贝
- 原型模式中对象的拷贝是二进制流的拷贝,并不会执行构造函数,因此要在构造函数中做一些额外操作的对象需要注意此问题
- kotlin中的Any类中是没有clone方法的
- 参考
- 代码:https://github.com/wk1995/DesignPattern