在开发过程中,我们常常会遇到需要创建多个实例的情况,而这些实例的都是相同的或者大部分内容是相同的,那么这个时候如果我们全部使用new()的方法来创建这些实例,将会花很多时间去创建,那么有没有更好的方法呢?当然有,我们可以使用复制(即clone)的方法来创建实例。这里就该我们要讲到的原型模式上场了。
一、原型模式包含的角色
我们可以看见其他模式都采用了继承或者多态的技术,而这里的原型模式是设计模式中比较简单的一种设计模式,因为没有使用继承和多态,而且模式的成员也比较简单。
(1)抽象原型类:声明了一个克隆自身的接口。
(2)具体原型类:实现了具体的克隆自身的操作。
二、浅拷贝和深拷贝
在这里我们要首先简单说一下深拷贝和浅拷贝,所谓在执行java的拷贝的时候,我们通常继承Cloneable接口,并且去实现里面的clone()方法,这里在我们要克隆一个对象的时候直接调用clone()方法就可以了,但是如果这个对象包含了引用属性呢?我们会发现克隆出来的引用属性和被克隆对象的引用属性是相同的,指向同一个引用地址。这是因为这种克隆方式并没有针对引用属性进行克隆和分配内存,这就是浅拷贝,那么要做到深拷贝,我们就应该在实现clone()方法的时候还应该对引用属性进行克隆。
三、具体示例
(1)浅拷贝原型模式
package com.liutao.design.model.prototype;
/**
* show the shallow copy of prototype model
*
* @author LIUTAO
* @version 2017/10/29
* @see
*/
public class ShallowResume implements Cloneable {
private String name;
private int age;
private ShallowWorkExperience shallowWorkExperience;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public ShallowWorkExperience getShallowWorkExperience() {
return shallowWorkExperience;
}
public void setShallowWorkExperience(ShallowWorkExperience shallowWorkExperience) {
this.shallowWorkExperience = shallowWorkExperience;
}
public ShallowResume() {
}
public ShallowResume(String name, int age, ShallowWorkExperience shallowWorkExperience) {
this.name = name;
this.age = age;
this.shallowWorkExperience = shallowWorkExperience;
}
public Object clone(){
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {
return "ShallowResume{" +
"name='" + name + '\'' +
", age=" + age +
", shallowWorkExperience=" + shallowWorkExperience +
'}';
}
}
被持有的对象
package com.liutao.design.model.prototype;
/**
* the experience of working to show shallow copy
*
* @author LIUTAO
* @version 2017/10/29
* @see
*/
public class ShallowWorkExperience {
private String companyName; //company name
private String companyAddress; // company address
public ShallowWorkExperience() {
}
public ShallowWorkExperience(String companyName, String companyAddress) {
this.companyName = companyName;
this.companyAddress = companyAddress;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public String getCompanyAddress() {
return companyAddress;
}
public void setCompanyAddress(String companyAddress) {
this.companyAddress = companyAddress;
}
@Override
public String toString() {
return "ShallowWorkExperience{" +
"companyName='" + companyName + '\'' +
", companyAddress='" + companyAddress + '\'' +
'}';
}
}
测试类
package com.liutao.design.model.prototype;
/**
* show how to use prototype
*
* @author LIUTAO
* @version 2017/10/29
* @see
*/
public class TestDemo {
public static void main(String[] args) {
ShallowWorkExperience shallowWorkExperience = new ShallowWorkExperience("华为","北京");
ShallowResume shallowResume = new ShallowResume("Joke",22,shallowWorkExperience);
ShallowResume shallowResumeCopy = (ShallowResume) shallowResume.clone();
shallowResumeCopy.setName("Rose");
shallowResumeCopy.setAge(21);
shallowResumeCopy.getShallowWorkExperience().setCompanyAddress("成都");
shallowResumeCopy.getShallowWorkExperience().setCompanyName("中兴");
System.out.println("shallowResume:"+shallowResume);
System.out.println("shallowResumeCopy:"+shallowResumeCopy);
}
}
运行结果
shallowResume:ShallowResume{name='Joke', age=22, shallowWorkExperience=ShallowWorkExperience{companyName='中兴', companyAddress='成都'}}
shallowResumeCopy:ShallowResume{name='Rose', age=21, shallowWorkExperience=ShallowWorkExperience{companyName='中兴', companyAddress='成都'}}
通过上面的运行结果我么可以看出对象再被克隆后,引用属性并没有进行克隆,而仅仅是复制了属性的引用地址,这就是浅复制。
(2)深复制原型模式
package com.liutao.design.model.prototype;
/**
* the experience of working to show deep copy
*
* @author LIUTAO
* @version 2017/10/29
* @see
*/
public class DeepWorkExperience implements Cloneable {
private String companyName; //company name
private String companyAddress; // company address
public DeepWorkExperience() {
}
public DeepWorkExperience(String companyName, String companyAddress) {
this.companyName = companyName;
this.companyAddress = companyAddress;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public String getCompanyAddress() {
return companyAddress;
}
public void setCompanyAddress(String companyAddress) {
this.companyAddress = companyAddress;
}
public Object clone(){
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {
return "ShallowWorkExperience{" +
"companyName='" + companyName + '\'' +
", companyAddress='" + companyAddress + '\'' +
'}';
}
}
我们可以看见在这个深度复制的原型模式当中引用属性的类也实现了Cloneable接口,并且实现了clone()方法。
package com.liutao.design.model.prototype;
/**
* show the shallow copy of prototype model
*
* @author LIUTAO
* @version 2017/10/29
* @see
*/
public class DeepResume implements Cloneable {
private String name;
private int age;
private DeepWorkExperience deepWorkExperience;
public DeepResume() {
}
public DeepResume(String name, int age, DeepWorkExperience deepWorkExperience) {
this.name = name;
this.age = age;
this.deepWorkExperience = deepWorkExperience;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public DeepWorkExperience getDeepWorkExperience() {
return deepWorkExperience;
}
public void setDeepWorkExperience(DeepWorkExperience deepWorkExperience) {
this.deepWorkExperience = deepWorkExperience;
}
public Object clone(){
try {
DeepResume deepResume = (DeepResume)super.clone();
deepResume.setDeepWorkExperience((DeepWorkExperience) this.getDeepWorkExperience().clone());
return deepResume;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {
return "DeepResume{" +
"name='" + name + '\'' +
", age=" + age +
", deepWorkExperience=" + deepWorkExperience +
'}';
}
}
从上面我们可以看出,在复制对象的时候也对对象的引用属性进行了一次复制。
测试类
package com.liutao.design.model.prototype;
/**
* show how to use prototype
*
* @author LIUTAO
* @version 2017/10/29
* @see
*/
public class TestDemo {
public static void main(String[] args) {
// DeepWorkExperience shallowWorkExperience = new DeepWorkExperience("华为","北京");
// DeepResume shallowResume = new DeepResume("Joke",22,shallowWorkExperience);
// DeepResume shallowResumeCopy = (DeepResume) shallowResume.clone();
// shallowResumeCopy.setName("Rose");
// shallowResumeCopy.setAge(21);
// shallowResumeCopy.getDeepWorkExperience().setCompanyAddress("成都");
// shallowResumeCopy.getDeepWorkExperience().setCompanyName("中兴");
// System.out.println("shallowResume:"+shallowResume);
// System.out.println("shallowResumeCopy:"+shallowResumeCopy);
DeepWorkExperience shallowWorkExperience = new DeepWorkExperience("华为","北京");
DeepResume shallowResume = new DeepResume("Joke",22,shallowWorkExperience);
DeepResume shallowResumeCopy = (DeepResume) shallowResume.clone();
shallowResumeCopy.setName("Rose");
shallowResumeCopy.setAge(21);
shallowResumeCopy.getDeepWorkExperience().setCompanyAddress("成都");
shallowResumeCopy.getDeepWorkExperience().setCompanyName("中兴");
System.out.println("shallowResume:"+shallowResume);
System.out.println("shallowResumeCopy:"+shallowResumeCopy);
}
}
测试结果
shallowResume:DeepResume{name='Joke', age=22, deepWorkExperience=ShallowWorkExperience{companyName='华为', companyAddress='北京'}}
shallowResumeCopy:DeepResume{name='Rose', age=21, deepWorkExperience=ShallowWorkExperience{companyName='中兴', companyAddress='成都'}}
我们可以看见这次克隆对象的引用属性也进行了克隆。