原型模式非常好理解,就是我们从原来的对象中复制出来一个一模一样的对象,俗称“克隆”,多用于创建复杂或者构造耗时的实例。
使用场景
1.类初始化需要消化非常多的资源,数据、硬件资源等。
2.通过new产生一个对象需要非常繁琐的数据准备或访问权限。
3.一个对象需要提供给其他对象使用,各个调用者可能需要修改其值,但是又要保证其属性独立不相互影响,也就是“保护性拷贝”。
比如A有一份文件要给B使用修改,但是A又不希望B更改自己的文件,所以就克隆一份供B使用。
注意:有时候通过实现Cloneable接口调用clone方法复制对象的时候并不比new快,所以要考虑创建成本。
具体实现
一个类去实现Cloneable接口
复写clone方法(这是Object类中的方法)
方法中:
XXXDoucument doc = (XXXDoucument)super.clone():
doc.mText = this.mText;
//....各种属性赋值。
return doc;
浅拷贝和深拷贝
浅拷贝对于引用类型只是拷贝了字段引用。
深拷贝对于引用型的字段也要使用clone的方式来拷贝。
Android源码中的原型模式:
intent类就可以调用.clone()方法
intent类中的clone方法里面就写了一句: return new Intent(this);
intent(Intent o)是一个拷贝构造函数,里面有大量诸如this.mAction = o.mAction的句子对属性进行设置。
实际应用:
比如我们有一个记录用户信息的UserSession类,里面有一个包级私有方法setUserInfo(UserInfo info)方法,这个方法只有在同包级的登录网络类从网络获得用户信息了才能调用,这个是没问题的。
可是保存用户信息的UserInfo实体类中的变量确是public的,会被人为修改。
为了只在网络访问获取用户信息后才去修改用户信息,避免在其他地方造成变化,我们让User继承Cloneable接口,复写clone方法
public User clone(){
User user = null;
try{
user = (User)super.clone();
}catch(CloneNotSupportedException e){
}
return user;
}
然后再UserSession中getLoginedUser里返回克隆类
return userInfo.clone();
这样在其他地方即使修改了userInfo对象,也不会影响从网络获取的最初的userInfo对象了。
优点:是在内存中直接进行二进制流拷贝,例如在一个循环体中大量的new对象时,使用clone性能会好很多。
缺点:因为是直接克隆对象,所以不会执行构造函数。要注意这一点。