目录
原型模式的定义
原型模式的使用场景
简单克隆
深度克隆
克隆破坏单例模式
Cloneable 源码分析
原型模式的优点
原型模式的缺点
原型模式的特点
先创建原型 Prototype 接口
public interface Prototype {
Prototype clone();
}
创建具体需要克隆的对象 ConcretePrototype
public class ConcretePrototype implements IPrototype {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public ConcretePrototype clone() {
ConcretePrototype concretePrototype = new ConcretePrototype();
concretePrototype.setAge(this.age);
concretePrototype.setName(this.name);
return concretePrototype;
}
@Override
public String toString() {
return "ConcretePrototype{" + "age=" + age + ", name='" + name + '\'' + '}';
}
}
测试代码
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("Tom");
System.out.println(prototype);
//拷贝原型对象
ConcretePrototype cloneType = prototype.clone();
System.out.println(cloneType);
}
运行结果
public class ConcretePrototype implements Cloneable {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "ConcretePrototype{" + "age=" + age + ", name='" + name + '\'' + '}';
}
}
public class ConcretePrototype implements Cloneable {
private int age;
private String name;
private List hobbies;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getHobbies() {
return hobbies;
}
public void setHobbies(List hobbies) {
this.hobbies = hobbies;
}
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "ConcretePrototype [age=" + age + ", name=" + name + ", hobbies=" + hobbies + "]";
}
}
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("prototype");
List hobbies = new ArrayList();
hobbies.add("复制");
hobbies.add("拷贝");
prototype.setHobbies(hobbies);
System.out.println(prototype);
//拷贝原型对象 ConcretePrototype
ConcretePrototype cloneType = prototype.clone();
cloneType.getHobbies().add("不留痕迹");
System.out.println("原型对象:" + prototype);
System.out.println("克隆对象:" + cloneType);
}
运行结果
我们给复制后的克隆对象新增一项爱好,发现原型对象也发生了变化,这显然不符合我们的预期。 因为我们希望克隆出来的对象应该和原型对象是两个独立的对象,不应该再有联系了。从测试结果分析来看,应该是 hobbies 共用了一个内存地址,意味着复制的不是值,而是引用的地址。这样的话,如果我们修改任意一个对象中的属性值,prototype 和 cloneType 的 hobbies 值都会改变。这就是我们常说的浅克隆。只是完整复制了值类型数据,没有赋值引用对象。换言之,所有的引用对象仍然指向原来的对象,显然不是我们想要的结果。那如何解决这个问题呢?下面我们来看深度克隆继续改造。
public class ConcretePrototype implements Cloneable,Serializable{
private int age;
private String name;
private List hobbies;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getHobbies() {
return hobbies;
}
public void setHobbies(List hobbies) {
this.hobbies = hobbies;
}
//浅克隆
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
//深克隆--将对象序列化到内存中在反序列化拿出来,得到一个新的对象
public Object deepClone() {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
oos.flush();
oos.close();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
ConcretePrototype clone = (ConcretePrototype)ois.readObject();
ois.close();
return clone;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "ConcretePrototype [age=" + age + ", name=" + name + ", hobbies=" + hobbies + "]";
}
}
测试代码
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("prototype");
List hobbies = new ArrayList();
hobbies.add("复制");
hobbies.add("拷贝");
prototype.setHobbies(hobbies);
System.out.println(prototype);
//拷贝原型对象 ConcretePrototype
ConcretePrototype cloneType = (ConcretePrototype) prototype.deepClone();
cloneType.getHobbies().add("不留痕迹");
System.out.println("原型对象:" + prototype);
System.out.println("克隆对象:" + cloneType);
System.out.println(prototype == cloneType);
System.out.println("原型对象的爱好:" + prototype.getHobbies());
System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
System.out.println(prototype.getHobbies() == cloneType.getHobbies());
}
运行结果
@Override
protected Object clone() throws CloneNotSupportedException {
return INSTANCE;
}
先来 JDK 中 Cloneable 接口
public interface Cloneable {
}
public Object clone() {
try {
ArrayList> v = (ArrayList>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
public ConcretePrototype deepCloneHobbies(){
try {
ConcretePrototype result = (ConcretePrototype)super.clone();
result.hobbies = (List)((ArrayList)result.hobbies).clone();
return result;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
测试代码
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("prototype");
List hobbies = new ArrayList();
hobbies.add("复制");
hobbies.add("拷贝");
prototype.setHobbies(hobbies);
System.out.println(prototype);
//拷贝原型对象 ConcretePrototype
ConcretePrototype cloneType = (ConcretePrototype) prototype.deepCloneHobbies();
cloneType.getHobbies().add("不留痕迹");
System.out.println("原型对象:" + prototype);
System.out.println("克隆对象:" + cloneType);
System.out.println(prototype == cloneType);
System.out.println("原型对象的爱好:" + prototype.getHobbies());
System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
System.out.println(prototype.getHobbies() == cloneType.getHobbies());
}
运行结果
运行也能得到期望的结果。但是这样的代码,其实是硬编码,如果在对象中声明了各种集合类型, 那每种情况都需要单独处理。因此,深克隆的写法,一般会直接用序列化来操作。
小结:
深度克隆的实现方式:
原型模式包含三个角色: