java设计模式-原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式。在java中,主要就是靠clone来复制对象,所以原型模式还是要先学习一下Cloneable这个接口。
浅克隆和深克隆
java中用基础类型和引用类型。基础类型就是String,Integer这些类型,引用类型就是对象,数组这些。
拿简历来说,简历里面有个人信息,和工作经历。个人信息包括姓名,年龄,性别,个人信息属于简历类里面的属性,工作经历则是另外一个类,在简历类里面引用它。
浅克隆就是只复制了个人信息,工作经历由于是引用对象,所以如果只是克隆简历类,则不管复制几个简历,里面的工作经历都只是引用同个对象。所以深克隆就是将工作经历也进行克隆。下面来看看代码
实现Cloneable接口
WorkExperience.java
public class WorkExperience implements Cloneable{
private String workDate;
private String company;
@Override
protected Object clone() {
Object object =null;
try {
object = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return object;
}
public WorkExperience(String workDate, String company) {
super();
this.workDate = workDate;
this.company = company;
}
get和set方法...
Resume.java(简历类)
public class Resume implements Cloneable{
private String name;
private String sex;
private String age;
private WorkExperience workExperience;
@Override
protected Object clone() {
Resume clone = null ;
try {
//对resume克隆
clone =(Resume)super.clone();
//对workExperience克隆,如果没有,就是浅克隆
clone.setWorkExperience((WorkExperience) workExperience.clone());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
public Resume(String name, String sex, String age) {
this.name = name;
this.sex = sex;
this.age = age;
}
get和set方法...
调用
public static void main(String[] args) {
Resume prototype = new Resume("小张", "3", "男");
WorkExperience workExperience = new WorkExperience("1996","company");
prototype.setWorkExperience(workExperience);
Resume clone1 = (Resume)prototype.clone();
System.out.println(prototype+"\n"+clone1+"\n");
System.out.println(prototype.getWorkExperience()+"\n"+
clone1.getWorkExperience());
}
打印结果
designPattern.prototypePattern.Resume@7852e922
designPattern.prototypePattern.Resume@4e25154f
designPattern.prototypePattern.WorkExperience@70dea4e
designPattern.prototypePattern.WorkExperience@5c647e05
可以看到结果,复制出来的clone1,包括里面的WorkExperience对象都和原来的不一样,实现了深度克隆。
这里的WorkExperience和Resume都实现了Cloneable接口,在克隆resume类的时候对resume和workexperience都进行克隆。
实现Serializable接口
除了Cloneable接口,还可以实现Serializable接口。
WorkExperience.java只需要声明实现接口就好,去掉clone方法,其余不需要变。
public class WorkExperience implements Serializable{}
Resume.java
public class Resume implements Serializable{
private static final long serialVersionUID = 7260158333965490347L;
private String name;
private String sex;
private String age;
private WorkExperience workExperience;
protected Object clone() {
Object object =null;
try {
//将对象写入流中
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream ooStream = new ObjectOutputStream(bos);
ooStream.writeObject(this);
//从流中读出对象
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream oIStream = new ObjectInputStream(bis);
object = oIStream.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return object;
}
public Resume(String name, String sex, String age) {
this.name = name;
this.sex = sex;
this.age = age;
}
}
调用和打印结果都一样。就不贴出来了。
这里是用序列化(Serialization)方式来实现克隆,可以看到WorkExperience和Resume都实现了Serialization接口。
序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。
可以看到,深克隆会比较复杂,耗时。对于浅克隆的缺点:引用对象会指向同一个地址,一个对象改变,另一个对象也会改变。如果我们的应用场景不会去更新这个引用对象,那么浅克隆也是可以接受的。或者如果只有部分对象会发生改变,我们可以使用浅克隆来克隆所有对象,然后再单独去深度克隆那些会发生改变的对象。