原型模式也是很简单的一种模式,对于java来说已经有相应的接口了(Cloneable)。关于原型模式<<大话设计模式>>是以投放简历作为例子讲解的,即我要投放很多简历,其实每个简历都一样,所以只要我写好一份,其他的复制就行了,其实就是今天讲的原型模式,就是把要复制的类对象的属性复制到另外一个对象上(其实不是复制而是对象的引用改变)。
原型模型:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
浅复制VS深复制
关于克隆有两个概念
浅复制:就是只复制值类型的字段,不能复制引用的对象。意思就是简历类中引用了其他的对象的话,这个引用对象的数据是不会复制的。
深复制:不进复制值类型的字段,还复制引用的对象。区别浅复制不复制引用对象,深复制复制引用对象。
让我们通过代码来更好的理解它们吧
浅复制代码
1、工作经历类(即将被简历类所引用)
/*
* 工作经历
*/
publicclass WorkExperienceSimple {
private StringtimeArea;
public String getTimeArea() {
returntimeArea;
}
publicvoid setTimeArea(String timeArea) {
this.timeArea = timeArea;
}
}
2、简历类(关键是实现了Cloneable接口)
/*
* 克隆中的浅复制代码
*/
publicclass ResumeSimpleimplements Cloneable {
private Stringname;
//private String timeArea;
public WorkExperienceSimpletimeArea;
public ResumeSimple(String name){
this.name = name;
timeArea =new WorkExperienceSimple();
}
publicvoid setWorkExperience(String workName){
timeArea.setTimeArea(workName);
}
publicvoid display(){
System.out.println("简历名称:"+name);
System.out.println("工作地址:"+timeArea.getTimeArea());
}
@Override
public Object clone()throws CloneNotSupportedException {
ResumeSimpleo = null;
try {
o = (ResumeSimple) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
3、客户端
publicclass PrototypeClient {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
//TODO Auto-generated method stub
//浅复制
System.out.println("--------浅复制开始----------");
ResumeSimpleresumeSimple =new ResumeSimple("大鸟");
resumeSimple.setWorkExperience("北京");
//克隆1,完美呈现
ResumeSimpleresumeSimple2;
try {
resumeSimple2= (ResumeSimple) resumeSimple.clone();
resumeSimple2.setWorkExperience("上海");
resumeSimple.display();
resumeSimple2.display();
}catch (CloneNotSupportedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
打印结果:
--------浅复制开始----------
简历名称:大鸟
工作地址:上海
简历名称:大鸟
工作地址:上海
看到了吧,工作经历都变成了上海,原来的北京没有被复制过来。这就是工作经历类没有被复制。
深复制
1、工作经历类(注意与浅复制区别)
/*
* 工作经历
* 与浅复制的区别1、实现了Cloneable接口2、实现接口的方法clone
*/
publicclassWorkExperienceDeepimplements Cloneable{
private StringtimeArea;
public String getTimeArea() {
returntimeArea;
}
publicvoid setTimeArea(String timeArea) {
this.timeArea = timeArea;
}
@Override
public Object clone()throws CloneNotSupportedException {
WorkExperienceDeep o =null;
try {
o = (WorkExperienceDeep)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
2、简历类(注意区别之处)
/*
* 克隆中的浅复制代码
* 与浅复制区别1、改变工作经历类的初始化方式,即增加构造函数ResumeDeep(WorkExperienceDeepworkName)
* 2、
*/
public class ResumeDeepimplements Cloneable {
private String name;
//private String timeArea;
public WorkExperienceDeep timeArea;
public ResumeDeep(String name){
this.name = name;
timeArea = new WorkExperienceDeep();
}
public ResumeDeep(WorkExperienceDeep workName){
try {
timeArea = (WorkExperienceDeep) workName.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void setWorkExperience(String workName){
timeArea.setTimeArea(workName);
}
public void display(){
System.out.println("简历名称:"+name);
System.out.println("工作地址:"+timeArea.getTimeArea());
}
@Override
public Object clone(){
ResumeDeep o = new ResumeDeep(this.timeArea); //目的对工作经历进行深复制
o.setName(name);
return o;
}
public void setName(String name) {
this.name = name;
}
}
3、客户端
publicclass PrototypeClient {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
//TODO Auto-generated method stub
//浅复制
System.out.println("--------浅复制开始----------");
ResumeSimpleresumeSimple =new ResumeSimple("大鸟");
resumeSimple.setWorkExperience("北京");
//克隆1,完美呈现
ResumeSimpleresumeSimple2;
try {
resumeSimple2= (ResumeSimple) resumeSimple.clone();
resumeSimple2.setWorkExperience("上海");
resumeSimple.display();
resumeSimple2.display();
}catch (CloneNotSupportedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
//深复制
System.out.println("--------深复制开始----------");
ResumeDeepresumeDeep = new ResumeDeep("大鸟");
resumeDeep.setWorkExperience("北京");
//克隆1,完美呈现
ResumeDeepresumeDeep2;
resumeDeep2= (ResumeDeep) resumeDeep.clone();
resumeDeep2.setWorkExperience("上海");
resumeDeep.display();
resumeDeep2.display();
}
}
打印结果:
--------浅复制开始----------
简历名称:大鸟
工作地址:上海
简历名称:大鸟
工作地址:上海
--------深复制开始----------
简历名称:大鸟
工作地址:北京
简历名称:大鸟
工作地址:上海
很明显深复制把工作经历类也复制了过来,所以原来的北京值没有变化。
附上原型模式结构图:
总结:浅复制对于值类型没有问题,对于引用类型,就只是复制了引用,对引用的对象还是只向了原来的对象,所以会出现两个引用设置的“工作经历”,但是都是应用的最后的那个设置值,因为两个引用指向了同一个对象。但我们可能需要这样一种需求,把要复制的对象所引用的对象都复制一遍,那么我们就可以选择深复制的方式了。