原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。
Java提供了Cloneable接口,只需要实现这个接口就可以完成原型模式了。
Java的所有类都是从java.lang.Object类继承而来的,而Object类提供protected Object clone()方法对对象进行复制,子类当然也可以把这个方法置换掉,提供满足自己需要的复制方法。对象的复制有一个基本问题,就是对象通常都有对其他对象的引用。当使用Object类的clone()方法来复制一个对象时,此对象对其他对象的引用也同时会被复制一份。
Java语言提供的Cloneable接口只起一个作用,就是在运行时期通知Java虚拟机可以安全地在这个类上使用clone()方法。通过调用这个clone()方法可以得到一个对象的复制。由于Object类本身并不实现Cloneable接口,因此如果所考虑的类并没有实现Cloneable接口时,调用clone()方法会抛出CloneNotSupportedException异常。
简历的原型类:
public class Resume implements Cloneable {
private String name;
private String sex;
private String age;
private String timeArea;
private String company;
public Resume(String name) {
this.name = name;
}
// 设置个人信息
public void setPersonInfo(String sex, String age) {
this.sex = sex;
this.age = age;
}
// 设置工作经历
public void setWorkExperience(String timeArea, String company) {
this.timeArea = timeArea;
this.company = company;
}
@Override
public Object clone() {
Object object = null;
try {
object = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return object;
}
public String toString(){
return name + sex + age + timeArea + company;
}
}
调用:
Resume resume = new Resume("大牛");
resume.setPersonInfo("男", "24");
resume.setWorkExperience("2013-2014", "X公司");
Resume clone = (Resume) resume.clone();
clone.setWorkExperience("2014-2015", "Y公司");
System.out.println(resume.toString());
System.out.println(clone.toString());
打印结果:
大牛男242013-2014X公司
大牛男242014-2015Y公司
浅复制和深复制
clone()方法是这样,如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。
把工作经历单独抽取一个类:
public class WorkExperience {
private String timeArea;
private String company;
public String getTimeArea() {
return timeArea;
}
public void setTimeArea(String timeArea) {
this.timeArea = timeArea;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
简历类:
public class Resume implements Cloneable {
private String name;
private String sex;
private String age;
private WorkExperience work;
public Resume(String name) {
this.name = name;
this.work = new WorkExperience();
}
// 设置个人信息
public void setPersonInfo(String sex, String age) {
this.sex = sex;
this.age = age;
}
// 设置工作经历
public void setWorkExperience(String timeArea, String company) {
work.setTimeArea(timeArea);
work.setCompany(company);
}
@Override
public Object clone() {
Object object = null;
try {
object = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return object;
}
public String toString(){
return name + sex + age + work.getTimeArea() + work.getCompany();
}
}
同样的调用,输出结果是:
大牛男242014-2015Y公司
大牛男242014-2015Y公司
原因:“浅复制”,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
“深复制”把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
简历的深复制实现:
工作经历类:
public class WorkExperience implements Cloneable{
private String timeArea;
private String company;
public String getTimeArea() {
return timeArea;
}
public void setTimeArea(String timeArea) {
this.timeArea = timeArea;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
@Override
public Object clone() {
Object object = null;
try {
object = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return object;
}
}
简历类:
public class Resume implements Cloneable {
private String name;
private String sex;
private String age;
private WorkExperience work;
public Resume(String name) {
this.name = name;
this.work = new WorkExperience();
}
// 设置个人信息
public void setPersonInfo(String sex, String age) {
this.sex = sex;
this.age = age;
}
// 设置工作经历
public void setWorkExperience(String timeArea, String company) {
work.setTimeArea(timeArea);
work.setCompany(company);
}
@Override
public Object clone() {
Resume object = null;
try {
object = (Resume) super.clone();
object.work = (WorkExperience) work.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return object;
}
public String toString(){
return name + sex + age + work.getTimeArea() + work.getCompany();
}
}
同样调用的输出结果:
大牛男242013-2014X公司
大牛男242014-2015Y公司