Java设计模式之原型模式与深浅拷贝
2016-08-08 14:29
316 查看
概述
原型模式是一种创建型模式,允许用户从一个样板实例中复制出一个内部属性一致的对象,俗称为克隆.被复制出来的实例就是我们所称的原型.
多用在创建实例比较复杂或者耗时的情况下,因为复制一个已经存在的实例可以使程序运行更高效.
定义
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。使用场景
类初始化需要消化非常多的资源,通过原型拷贝避免这些消耗通过
new产生一个对象需要非常繁琐的数据准备或访问权限
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,保护原始对象.
UML类图
Client : 客户端用户。
Prototype : 抽象类或者接口,声明具备
clone能力。
ConcretePrototype : 具体的原型类.
原型模式主要用于对象的复制,其原型类(
ConcretePrototype)想要被复制,需要满足如下条件
实现
Cloneable接口,此接口相当于
Prototype角色.
复写
clone方法.并将其包访问权限修改为
public的.
Object中的
clone方法是受保护的,如果一个类实现了
Cloneable接口,
clone方法就会返回改对象的逐域拷贝,否则会抛出
CloneNotSupportedException异常
Cloneable接口中没有任何方法,它仅仅是一个标记接口,只有实现此接口的对象才能被拷贝。
对象的拷贝
在Java中,如果我们将原始对象的值赋给另一个对象,就是值的传递,如int a = 1; int b = a;
如果将引用类型的值赋给另一个对象,则是引用的传递,如
String[] a = new String[5]; String[] b = a;//这里b只是指向了a的引用
浅拷贝
如果我们只是实现了Cloneable接口,并简单的使用
super.clone()来复写
clone方法的话,那么基本上就是浅拷贝,浅拷贝对于引用类型就如上一样,并不是真正的拷贝.
public class Clone implements Cloneable{ private int mInt; private ArrayList mList; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } //.... }
CloneImpl cloneImpl = new CloneImpl(); //... try { Object clone = cloneImpl.clone(); CloneImpl cloneImpl1 = (CloneImpl) clone; //... } catch (CloneNotSupportedException e) { e.printStackTrace(); }
通过日志打印,可以看到源
mList的值会因为
clone实例的改变而改变.而
mInt值不变.
浅拷贝的特点:
对于引用类型,只拷贝其引用
效率高
不能完全做到保护性拷贝
浅拷贝适用于
对象只包含原始数据域或者不可变对象域的时候,提高效率
深拷贝
深拷贝可以做到保护性拷贝,看ArrayList的源码,我们发现其实现了
Cloneable接口,并重写了
clone()方法.因此,将上述代码修改为如下形式
@Override protected Object clone() throws CloneNotSupportedException { CloneImpl2 clone = (CloneImpl2) super.clone(); clone.mList = (ArrayList) mList.clone(); return clone; }
之后再次执行
clone()后,这是
clone实例的改变就不会影响到源对象了
深拷贝的特点:
复写
clone方法的时候,需要调用属性的
clone方法
做到
100%保护性拷贝
比浅拷贝耗时
当对象存在引用类型的属性,要使用深拷贝.为了防止错误的发生,在使用对象拷贝的时候,建议尽量使用深拷贝
注意事项
在Effective Java第11条,
要谨慎的覆盖clone中有这样的描述,
对于任何对象x,表达式 x.clone() != x 将会是 true x.clone().getClass() == x.getClass() 将会是 true,但不是绝对要求 x.clone().equals(x) 将会是 true,但也不是绝对的要求 拷贝对象会创建一个类新的实例,并会拷贝其内部结构,但是不会调用构造器
原型模式中对象的拷贝是二进制流的拷贝,并不会执行构造函数,因此要在构造函数中做一些额外操作的对象需要注意此问题
因为其忽略了构造函数(包括其访问权限),所以和单例模式是冲突的,因为单例模式将构造函数设为
private的.
尽量使用深拷贝类防止错误的发生,对于只有值域类型的对象使用浅拷贝
原型模式中的
原型与
clone实例通过
equals和
==比较返回值都是
false
有些对象的
clone()方法是直接
new一个对象,如
Intent,需要根据创建对象的复杂程度来决定.
对于对象中包含
final关键字的拷贝无法编译通过
Object中的
clone()方法是线程不同步的.在需要线程安全的场景,需要做好同步工作.
对象的拷贝还有其他方式,如序列化接口
Serializable
实例代码
DesignPatterns相关文章推荐
- Java设计模式之原型模式与深浅拷贝
- 设计模式(Design Patterns)-可复用面向对象软件的基础 05:原型模式(Prototype)和Java中的深、浅拷贝
- java 设计模式学习笔记(8) - 原型模式
- java设计模式连载(4) --原型模式
- [原译]理解并实现原型模式-实现ICloneable接口.理解深浅拷贝
- java设计模式——原型模式(Prototype)
- 设计模式(五)----- 原型模式(Prototype)----(JAVA版)
- Java设计模式(二)Prototype(原型),Builder和Singleton(单态)
- java设计模式--原型设计模式 Prototype
- 理解并实现原型模式-实现ICloneable接口.理解深浅拷贝 转
- Java设计模式:原型模式
- Java设计模式 创建模式-原型模式(Prototype)
- java软件体系设计模式----原型
- Java设计模式四: 原型模式(Prototype Pattern)
- Java设计模式 - Prototype(原型模式)
- Java设计模式:Prototype(原型)
- Java设计模式-----Prototype原型模式
- java设计模式--原型设计模式 Prototype
- JAVA设计模式 — 原型模式(Prototype)
- java设计模式(五)创建者模式和原型模式