一、引
我们在日常的开发中,可能会遇到需要重复创建相同或者类似的对象,这个时候如果使用实例化(new),那么我们需要多少个对象,就需要实例化多少次,这不仅会导致代码重复的灾难,还难以对已实例化的对象进行修改,那么这个时候就需要一种设计思想,在需要对象的时候,尽量避免实例化,优化程序结构,且方便我们进行修改,这种模式就是原型模式,可以理解为利用原型进行复制。
二、问题
有一个简历的类(Resume),现在需要多份简历,如果通过一份简历复制多份?
三、理解及实现
这个时候有人会说,这还不简单new一个类,然后不断的赋值就好了,像下列这样:
Resume a = new Resume();
Resume b = a;
Resume c = b;
会这样写的,说明基础还不够扎实,因为,java中对象的单纯赋值,并不是复制一个新的对象,而是引用,所以要注意了,不能这么写,那么要怎么写呢?思路很简单,我们需要先实例化一个对象,然后通过这个对象复制(结构+数据)出无数的新对象,这样每个对象都是独立的,而且还能在原对象数据的基础上进行更改,方便很多,说起来容易,我们要怎么做呢?我们先来看看原型模式的结构图:
从图中我们可以理解到,需要定义一个原型抽象类,这个类有一个克隆的接口,一般在实体类的这个接口中,使用克隆方法进行克隆,但是由于克隆实在是太常用了,所以java早就给我们定义好了这个抽象类(Cloneable),所以我们的实体类直接实现这个接口就行了。具体代码如下:
public class Resume implements Cloneable {
private String name;
private String sex;
private int age;
private WorkExperience workExperience;
public Resume(String name) {
this.name = name;
workExperience = new WorkExperience();
}
public void setName(String name) {
this.name = name;
}
public void setPersonal(String sex, int age) {
this.age = age;
this.sex = sex;
}
public void setWork(String timeArea, String company) {
workExperience.timeArea = timeArea;
workExperience.company = company;
}
@Override
public Resume clone() throws CloneNotSupportedException {
return (Resume)super.clone();
}
public void display() {
System.out.println(this.name + " " + this.sex + " " + this.age + " " + this.sex);
System.out.print("Work experience: " + this.workExperience.timeArea);
System.out.println(" " + this.workExperience.company);
}
}
public class WorkExperience {
public String timeArea = null;
public String company = null;
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Resume resume1 = new Resume("Jobs");
resume1.setPersonal("Male", 26);
resume1.setWork("2016年8月1日 - 2018年6月30日", "Huawei");
Resume resume2 = resume1.clone();
resume2.setName("Tom");
resume2.setWork("2018年7月1日 - 2019年1月10日", "Baidu");
resume1.display();
resume2.display();
}
}
运行之后,你会发现一件很奇怪的事情,就是名字正常的更改了,但两个对象的工作经历都变成了最后一次更改时的值,这是怎么回事呢?这就涉及到了浅复制和深复制的概念。因为clone这个方法,对于值类型的属性进行逐位复制,但对于引用的对象,只复制引用而不复制引用的对象,所以,在例子中WorkExperience是被引用的对象,所以例子中的两个对象都在对一个WorkExperience实例进行修改,才会导致以上的问题,这就是浅复制,那么我们如何进行深复制呢?我们在clone进行操作就行,代码如下:
@Override
public Resume clone() throws CloneNotSupportedException {
int age = this.age;
String sex = this.sex;
String name = new String(this.name);
Resume copy = new Resume(name, famMem);
copy.setPersonal(sex, age);
copy.setWork(this.work.timeArea, this.work.company);
return copy;
}