原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
java 可以通过实现 Cloneable 接口重写 clone 方法来实现原型模式。
原型模式不用重新初始化对象,而是动态的获得对象运行时的状态,隐藏了对象创建的细节,对性能大大提高。
clone 方法复制的过程是这样的,如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象,因此原始对象及其副本引用同一对象。
浅复制示例:
public class Resume implements Cloneable {
private String name;
private String age;
private String sex;
private WorkExperience workExperience;
public Resume(String name) {
this.name = name;
workExperience = new WorkExperience();
}
public void setPersonalInfo(String age, String sex) {
this.age = age;
this.sex = sex;
}
public void setWorkExperience(String timeArea, String company) {
workExperience.setTimeArea(timeArea);
workExperience.setCompany(company);
}
public void Display() {
System.out.println(name + age + sex);
System.out.println(workExperience.getTimeArea() + workExperience.getCompany());
}
public Resume clone() throws CloneNotSupportedException {
return (Resume) super.clone();
}
}
//该类有两个字段和get、set方法
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 static void main(String[] args) throws CloneNotSupportedException {
// TODO Auto-generated method stub
Resume aResume = new Resume("人员A");
aResume.setPersonalInfo("1岁", "m");
aResume.setWorkExperience("2010-2020", "A公司");
Resume bResume = aResume.clone();
bResume.setPersonalInfo("2岁", "w");
bResume.setWorkExperience("2020-2030", "B公司");
bResume.Display();
aResume.Display();
}
输出:
人员A 2岁 w
2020-2030 B公司
人员A 1岁 m
2020-2030 B公司
被复制对象的所有变量都含有原来的对象的值,而所有对其他对象的引用都仍然指向原来的对象。
修改为深复制:
//实现 Cloneable 接口
public class WorkExperience implements Cloneable {
...
//其余方法属性不变
...
public WorkExperience clone() throws CloneNotSupportedException {
return (WorkExperience) super.clone();
}
}
public class Resume implements Cloneable {
...
//其余方法属性不变
...
public Resume clone() throws CloneNotSupportedException {
Resume aResume = (Resume) super.clone();
aResume.workExperience = workExperience.clone();
return aResume;
}
}
测试用例输出:
人员A 2岁 w
2020-2030 B公司
人员A 1岁 m
2010-2020 A公司
需要注意的是:
数组的clone,仅仅复制的是数组中的元素,即若数组中元素为引用类型,仅仅复制引用。
若clone的对象中含有链表,则应单独对链表进行循环复制。