一、前言
设计模式系列(参考资料:《Android源码设计模式解析与实战》——何红辉、关爱明)
单例模式
Builder模式
原型模式
二、介绍
原型模式属于创建型模式
,主要通过从一个现有实例拷贝
出另外一个实例,从而实现两个实例互不影响(这是深拷贝,浅拷贝还是会有影响的)
三、UML图
这里有三个角色是因为
面向接口,所以以多态的形式创建具体原型类ConcretePrototype,实际上接口Prototype选择性创建
四、使用场景
根据原型模式的特点——克隆,可以得出以下使用场景:
- 1、因为
clone
方法不会调用构造函数,所以如果new
一个对象代价太高(例如需要繁琐的数据准备、权限,或耗时较长),可以选择原型模式
代替 - 2、一个对象需要提供给其他对象使用,而且使用者有可能需要各自改变它们拿到的这个对象的值,这时候就不可以直接返回同一个对象了,因为这样会导致
A使用者
的修改同步到B使用者
的对象
五、举例
场景:用户登录后生成一个用户信息记录,供其它类调用(不是修改)
用户记录类,setUser
方法的级别为包级,也就限制了其他包调用该方法
public class UserRecord {
private UserRecord mUserRecord = null;
private User mUser = null;
public UserRecord() {
}
//包级
void setUser(User user){
mUser = user;
}
public UserRecord getUserRecord(){
if (mUserRecord == null){
mUserRecord = new UserRecord();
}
return mUserRecord;
}
//得到的并不是mUser,而是一个克隆对象
public User getUser() throws CloneNotSupportedException{
return (User) mUser.clone();
}
}
User
实体类,重写了clone
方法,该方法返回一个User
的克隆对象,这样就可以防止多个调用方对mUser
进行修改,从而互相影响(这里注意TestObject,如果只clone了User对象,那是浅拷贝,如果要达到深拷贝,需要把它下面的所有引用数据类型,例如TestObject也通过clone拷贝)
public class User implements Cloneable {
private int mId;
private String mName;
private TestObject mObject;
public TestObject getmObject() {
return mObject;
}
public void setmObject(TestObject mObject) {
this.mObject = mObject;
}
public int getmId() {
return mId;
}
public void setmId(int mId) {
this.mId = mId;
}
public String getmName() {
return mName;
}
public void setmName(String mName) {
this.mName = mName;
}
@NonNull
@NotNull
@Override
protected Object clone() throws CloneNotSupportedException {
User out = null;
try {
out = (User) super.clone();
//深拷贝
out.mObject = (TestObject) mObject.clone();
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return out;
}
}
六、总结
原型模式固然有其优点,例如可以绕过繁琐的构造函数,从而快速创建对象。但是缺点也一样很明显,那就是会产生多个对象,而每个对象都需要分配内存,关于取舍需要按照业务和产品需求来决定