一、概述
1、定义
原型模式,用原型示例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
2、结构图
原型模式其实就是从一个对象创建另外一个可定制的对象,而且不需要知道任何创建的细节。
二、实现方式
1、调用api
protected native Object clone() throws CloneNotSupportedException;
说明:需要重写Object类的clone方法
2、使用方式
如果要克隆一个类的实例,这个类必须:
- 实现Cloneable接口。
- 使用public访问修饰符重新定义clone方法
注:使用clone方法对一个对象进行克隆时,默认是对该对象进行浅复制的,而在开发中通常需要对对象进行深复制。
浅复制:若要克隆的对象的成员变量是数值或基本类型,则直接将成员变量的值复制一份;若成员变量是引用类型,则只复制成员变量的引用地址,即复制后的成员变量与原变量引用同一个对象(若成员变量是不可变的引用类型如String,则情况与基本类型一样)。
深复制:无论是基本类型或是引用类型,都将成员变量的引用的对象复制一遍,复制后的变量引用新的对象。
三、代码实现
1、场景
用代码实现简历的复制,简历中包含个人信息和工作经历
2、代码清单
3、浅复制
package prototype.light;
/**
* @ClassName: WorkExperience
* @Description: 工作经历类
* @author kooking
* @date 2018-7-3 下午8:17:36
*/
public class WorkExperience{
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;
}
public WorkExperience(String workDate, String company) {
super();
this.workDate = workDate;
this.company = company;
}
public WorkExperience() {
}
}
package prototype.light;
/**
* @ClassName: Resume
* @Description: 简历类(浅复制)
* @author kooking
* @date 2018-7-3 下午8:22:25
*/
public class Resume implements Cloneable {
private String name;
private String sex;
private String age;
private WorkExperience work;
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 String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public WorkExperience getWork() {
return work;
}
public void setWork(WorkExperience work) {
this.work = work;
}
public Resume() {
}
public Resume(String name, String sex, String age, WorkExperience work) {
super();
this.name = name;
this.sex = sex;
this.age = age;
this.work = work;
}
public void display(){
System.out.println(name+" ,"+sex+","+age);
System.out.println("工作经历:"+work.getWorkDate()+" "+work.getCompany());
}
/* (non-Javadoc)
* Title: clone
* Description: 重写clone方法
* @return
* @throws CloneNotSupportedException
* @see java.lang.Object#clone()
*/
@Override
public Resume clone() throws CloneNotSupportedException {
return (Resume) super.clone();
}
}
package prototype.light;
/**
* @ClassName: LightClone
* @Description: 浅复制测试类
* @author kooking
* @date 2018-7-3 下午8:50:44
*/
public class LightClone {
public static void main(String[] args) throws Exception{
//原型
Resume originalResume=new Resume("大鸟","男","29",new WorkExperience("1998-2000", "xx公司"));
//由原型克隆出来的A简历
Resume cloneA= originalResume.clone();
cloneA.getWork().setWorkDate("1998-2006");
cloneA.getWork().setCompany("yy公司");
// 由原型克隆出来的B简历
Resume cloneB = originalResume.clone();
cloneB.getWork().setWorkDate("1998-2003");
cloneB.getWork().setCompany("zz公司");
originalResume.display();
cloneA.display();
cloneB.display();
//查看对象
System.out.println(originalResume+"--"+originalResume.getWork());
System.out.println(cloneA+"--"+cloneA.getWork());
System.out.println(cloneB+"--"+cloneB.getWork());
}
}
测试结果
大鸟 ,男,29
工作经历:1998-2003 zz公司
大鸟 ,男,29
工作经历:1998-2003 zz公司
大鸟 ,男,29
工作经历:1998-2003 zz公司
prototype.light.Resume@1db05b2--prototype.light.WorkExperience@530cf2
prototype.light.Resume@76fba0--prototype.light.WorkExperience@530cf2
prototype.light.Resume@181ed9e--prototype.light.WorkExperience@530cf2
4、深复制
package prototype.deep;
/**
* @ClassName: WorkExperience_Deep
* @Description: 工作经历类(深复制)
* @author kooking
* @date 2018-7-3 下午9:03:03
*/
public class WorkExperience_Deep 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;
}
public WorkExperience_Deep(String workDate, String company) {
super();
this.workDate = workDate;
this.company = company;
}
public WorkExperience_Deep() {
}
/* (non-Javadoc)
* Title: clone
* Description: 重写clone方法
* @return
* @throws CloneNotSupportedException
* @see java.lang.Object#clone()
*/
@Override
public WorkExperience_Deep clone() throws CloneNotSupportedException {
return (WorkExperience_Deep) super.clone();
}
}
package prototype.deep;
/**
* @ClassName: Resume_Deep
* @Description: 简历类(深复制)
* @author kooking
* @date 2018-7-3 下午8:54:16
*/
public class Resume_Deep implements Cloneable {
private String name;
private String sex;
private String age;
private WorkExperience_Deep work;
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 String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public WorkExperience_Deep getWork() {
return work;
}
public void setWork(WorkExperience_Deep work) {
this.work = work;
}
public Resume_Deep() {
}
public Resume_Deep(String name, String sex, String age, WorkExperience_Deep work) {
super();
this.name = name;
this.sex = sex;
this.age = age;
this.work = work;
}
public void display(){
System.out.println(name+" ,"+sex+","+age);
System.out.println("工作经历:"+work.getWorkDate()+" "+work.getCompany());
}
/* (non-Javadoc)
* Title: clone
* Description: 重写clone方法
* @return
* @throws CloneNotSupportedException
* @see java.lang.Object#clone()
*/
@Override
public Resume_Deep clone() throws CloneNotSupportedException {
Resume_Deep resume=(Resume_Deep) super.clone();
resume.work=(WorkExperience_Deep) this.work.clone();
return resume;
}
}
package prototype.deep;
/**
* @ClassName: DeepClone
* @Description: 深复制测试类
* @author kooking
* @date 2018-7-3 下午9:11:53
*/
public class DeepClone {
public static void main(String[] args) throws CloneNotSupportedException {
//原型
Resume_Deep originalResume=new Resume_Deep("大鸟","男","29",
new WorkExperience_Deep("1998-2000", "xx公司"));
//由原型克隆出来的A简历
Resume_Deep cloneA=originalResume.clone();
cloneA.getWork().setWorkDate("1998-2006");
cloneA.getWork().setCompany("yy公司");
// 由原型克隆出来的B简历
Resume_Deep cloneB = originalResume.clone();
cloneB.getWork().setWorkDate("1998-2003");
cloneB.getWork().setCompany("zz公司");
originalResume.display();
cloneA.display();
cloneB.display();
//查看对象
System.out.println(originalResume+"--"+originalResume.getWork());
System.out.println(cloneA+"--"+cloneA.getWork());
System.out.println(cloneB+"--"+cloneB.getWork());
}
}
测试结果
大鸟 ,男,29
工作经历:1998-2000 xx公司
大鸟 ,男,29
工作经历:1998-2006 yy公司
大鸟 ,男,29
工作经历:1998-2003 zz公司
prototype.deep.Resume_Deep@18b3364--prototype.deep.WorkExperience_Deep@1db05b2
prototype.deep.Resume_Deep@530cf2--prototype.deep.WorkExperience_Deep@76fba0
prototype.deep.Resume_Deep@181ed9e--prototype.deep.WorkExperience_Deep@1175422
四、总结
1、优点
简化对象创建过程,提高效率。
2、缺点
实现深复制时可能需要比较复杂的代码。
3、适用场景
原型模式通常在以下情况使用:
通过其构造方法创建一个对象需要耗时很久或者消耗很多资源时,可以考虑使用原型模式。
(使用clone方法创建对象不需要调用其构造方法,它的本质是在内存中复制对象)