今天来学习设计模式中的原型模式,原型模式分为两种,一种是“浅复制”,一个是“深复制”。
先来说原型模式,原型模式说白了,就是一种复制模式,将已经新建好的对象,通过复制的形式,来给另一个对象赋值,在效率上,要远远好于new方式来实例化对象。
在复制的时候,会有一些问题,就是,默认的复制只会复制java的基本类型,包括String,但是对于类中的对象,只是复制它的引用,并没有从根本上去复制。举个例子:默认的复制方式就是,比如在内存中有一个值A,地址为1号(这里地址为假设的,为了方便所以这么写,真实的内存地址不是这样的),现在我声明了一个变量One,让这个变量One等于1号,最终的结果就是One=A,现在我用One克隆了一个Two,但是这个Two指向的地址也是1号,所以Two=A,表面上看没错,但是当Two操作这个A的时候,One里的A也会随着变化。不知道我说明白了没,我话一张图,大家就会明白许多。
看了这个图,我想大家会明白许多,所以不管是One还是Two,他们操作的是一个对象,One里修改,Two也会修改,反之也一样,这可不是我们想要的。我们想要的是下边的这个结果。
这才是我们要的结果,所以,原型模式就有了“浅复制”,“深复制”的区别。
我们来看一看怎么实现
包结构
先看看浅复制
新建一个people方法,存放人的姓名和年龄
package com.prototype.shallow.clone;
public class People implements Cloneable {
private String peopleName;
private int peopleAge;
public People() {
super();
System.out.println("执行了People的构造方法");
}
public String getPeopleName() {
return peopleName;
}
public void setPeopleName(String peopleName) {
this.peopleName = peopleName;
}
public int getPeopleAge() {
return peopleAge;
}
public void setPeopleAge(int peopleAge) {
this.peopleAge = peopleAge;
}
public Object clone() {
People people = null;
try {
people = (People) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return people;
}
}
注意这里要实现一个Cloneable接口,然后要写一个Clone方法,调用Object的clone方法,很简单
来看一下怎么调用
package com.prototype.shallow.main;
import com.prototype.shallow.clone.People;
public class ShallowMain {
public static void main(String[] args) {
People people1 = new People();
people1.setPeopleName("小明");
people1.setPeopleAge(20);
//克隆第二个对象
People people2 = (People) people1.clone();
people2.setPeopleAge(30);
<pre name="code" class="java"> System.out.println("姓名:"+people1.getPeopleName()+",年龄:"+people1.getPeopleAge());
System.out.println("姓名:"+people2.getPeopleName()+",年龄:"+people2.getPeopleAge());}}
运行结果如下
是不是很简单?而且要注意,上边的构造方法值执行了一次,所以克隆方法是不会再去执行构造方法的,是直接对jvm的数据操作,效率当然比new这种方式高很多。
如果,这个people对象里有其他对象存在的话,上边的这个方法就行不通了,这时就要用到深复制了
还是上边的那个例子
package com.prototype.deep.clone;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class People implements Cloneable,Serializable{
private static final long serialVersionUID = 1L;
private String peopleName;
private int peopleAge;
private WorkExperience workExperience;
public People() {
super();
System.out.println("执行了People的构造方法");
}
public String getPeopleName() {
return peopleName;
}
public void setPeopleName(String peopleName) {
this.peopleName = peopleName;
}
public int getPeopleAge() {
return peopleAge;
}
public void setPeopleAge(int peopleAge) {
this.peopleAge = peopleAge;
}
public WorkExperience getWorkExperience() {
return workExperience;
}
public void setWorkExperience(WorkExperience workExperience) {
this.workExperience = workExperience;
}
public Object deepClone() throws IOException, ClassNotFoundException {
//将对象写到流里
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//从流里读回来
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
我在people里增加了一个对象,而且注意,我该写了deepClone方法,这才是深复制的区别所在
WorkExperience类,工作经历类
package com.prototype.deep.clone;
import java.io.Serializable;
public class WorkExperience implements Serializable {
private static final long serialVersionUID = 1L;
private String companyName;
private double workTime;
public WorkExperience() {
super();
System.out.println("执行了WorkExperience的构造方法");
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public double getWorkTime() {
return workTime;
}
public void setWorkTime(double workTime) {
this.workTime = workTime;
}
}
调用的时候和之前差不多
package com.prototype.deep.main;
import com.prototype.deep.clone.People;
import com.prototype.deep.clone.WorkExperience;
public class DeepMain {
public static void main(String[] args) {
People people1 = new People();
WorkExperience workExperience = new WorkExperience();
workExperience.setCompanyName("XXX公司");
workExperience.setWorkTime(2.5);
people1.setPeopleName("小明");
people1.setPeopleAge(20);
people1.setWorkExperience(workExperience);
People people2 = null;
try {
people2 = (People) people1.deepClone();
people2.getWorkExperience().setWorkTime(10.5);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("姓名:"+people1.getPeopleName()+",年龄:"+people1.getPeopleAge()+",工作公司:"+people1.getWorkExperience().getCompanyName()+",工作年限:"+people1.getWorkExperience().getWorkTime());
System.out.println("姓名:"+people2.getPeopleName()+",年龄:"+people2.getPeopleAge()+",工作公司:"+people2.getWorkExperience().getCompanyName()+",工作年限:"+people2.getWorkExperience().getWorkTime());
}
}
运行结果
这里才达到了我们的要求。
同时要注意,要进行复制的对象一定要实现Serializable接口,否则会抛异常。
一般来说,原型模式单独来用的情况不是很多,通常会和其他模式混合使用。