定义:
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式就是从一个对象再创建另外一个可制定的对象,而且不需要知道任何创建的细节。
结构图
Prototype:原型抽象类,保存类的数据和申明克隆自身的接口。
ConcretePrototype:具体原型类,不同的实现会导致克隆的方式不同。
Client:客户端类。
对于Java而言,那个原型抽象类用不着,因为有一个Cloneable接口,需要克隆的对象只需要实现实现Cloneable接口然后按照需求重写clone方法。
深克隆与浅克隆
浅克隆:只复制了普通变量,而引用变量还是共用一份。
深克隆:复制了普通变量和引用变量,引用变量不再共用一份。
Java中可以用序列化和实现Cloneable接口且实现clone()的方法实现深克隆。
在java中普通只实现了Cloneable接口,并在重写时只调用spuer.clone(),只是浅拷贝(Object类的clone方法只是浅拷贝),只会拷贝普通的属性,如果需要拷贝引用属性,属性类得实现Cloneable接口,属性类得有支持深拷贝的clone方法,且在类的Clone方法中需要自己写复制引用属性的部分给新对象。
关于Cloneable接口和clone方法
1.Object中的clone执行的时候使用了RTTI(run-time type identification)的机制,动态得找到目前正在调用clone方法的那个reference,根据它的大小申请内存空间,然后进行bitwise的复制,将该对象的内存空间完全复制到新的空间中去,从而达到shallowcopy的目的。
所以你调用super.clone() 得到的是当前调用类的副本,而不是父类的副本。根本没有必用调用this.clone();
2.要让实例调用clone方法就需要让此类实现Cloneable接口,API里面还有句话是:如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常,这便是“合法”的含义。 但请注意,Cloneable接口只是个标签接口,不含任何需要实现的方法,就像Serializable接口一样。
实例
复制简历
简历实体类:
public class Resume implements Cloneable{
private String name;
private String sex;
private int age;
private WorkExperience workExperience;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public WorkExperience getWorkExperience() {
return workExperience;
}
public void setWorkExperience(WorkExperience workExperience) {
this.workExperience = workExperience;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//简历的类浅复制
Resume obj = (Resume) super.clone();
//复制引用属性
obj.setWorkExperience((WorkExperience)this.workExperience.clone());
return obj;
}
}
工作经历类:
public class WorkExperience implements Cloneable{
private String workDate;
private String company;
public String getWorkDate() {
return workDate;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
客户端类:
public class Client {
public static void main(String[] args) {
Resume resume = new Resume();
resume.setName("A同学");
resume.setAge(20);
resume.setSex("男");
WorkExperience workExperience = new WorkExperience();
workExperience.setCompany("T公司");
workExperience.setWorkDate("2017年");
resume.setWorkExperience(workExperience);
try {
Resume obj = (Resume) resume.clone();
workExperience.setCompany("A公司");
System.out.println(obj.getWorkExperience().getCompany());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
最终的输出结果是:T公司
证明确实复制了引用。而不是共用原来的引用。