Java 设计模式:原型Prototype
原型模式Prototype
原型模式也是一种对象创建的模式,主要作用是通过拷贝已有对象来生成新对象。它的好处是在实例化对象时不用每一次都使用新建,这样如果在新建对象比较耗时的情况下可以提高程序的运行效率。
原型模式中的拷贝分为浅拷贝和深拷贝
浅拷贝: 对对象中的值类型进行拷贝,对引用类型不拷贝还是指向相同的引用;
深拷贝: 对对象中的值类型进行拷贝,对引用类型也拷贝;
示例:
现有简历类,类的属性有姓名、年龄和工作经验,工作经验为引用类型包括公司名称和工作时间
浅拷贝代码如下:
工作经验类 WorkExperience
class WorkExperience { private String companyName; private int years; public WorkExperience (String cname , int years ) { this.companyName = cname ; this.years = years; } public String getCompanyName() { return companyName; } public void setCompanyName(String companyName) { this.companyName = companyName; } public int getYears() { return years; } public void setYears(int years) { this.years = years; } }
简历类 Resume
class Resume implements Cloneable { private WorkExperience workExperience ; private String name ; private int age ; public Resume(WorkExperience workExperience, String name, int age) { super(); this.workExperience = workExperience; this.name = name; this.age = age; } public WorkExperience getWorkExperience() { return workExperience; } public void setWorkExperience(WorkExperience workExperience) { this.workExperience = workExperience; } 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 Object clone() { try { return super.clone(); //直接调用父类的clone方法 } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); return null ; } } }
运行测试1:创建两个工作经验类we1和we2,创建简历类r1 并通过拷贝创建简历类r2.通过set方法修改简历r2的姓名、年龄和工作经验
public class ProtoType { public static void main (String args[]) { WorkExperience we1 = new WorkExperience("公司A", 2); WorkExperience we2 = new WorkExperience("公司B", 3); Resume r1 = new Resume(we1, "小张", 24); Resume r2= (Resume)r1.clone() ; r2.setName("小李"); r2.setAge(30); r2.setWorkExperience(we2); System.out.println(r1.getName()+r1.getAge()+"岁,工作经验"+r1.getWorkExperience().getCompanyName()+","+r1.getWorkExperience().getYears()+"年"); System.out.println(r2.getName()+r2.getAge()+"岁,工作经验"+r2.getWorkExperience().getCompanyName()+","+r2.getWorkExperience().getYears()+"年"); } }
运行结果如下
小张24岁,工作经验公司A,2年 小李30岁,工作经验公司B,3年
简历类r2 通过set方法修改属性值后未影响r1.
运行测试2:创建一个工作经验类we,创建简历类r1并通过克隆创建简历类r2 。r2通过set方法修改属性值name、age,并通过getWorkExperience()获取工作经验类后修改工作经验。代码如下
public class ProtoType { public static void main (String args[]) { WorkExperience we = new WorkExperience("公司A", 2); Resume r1 = new Resume(we, "小张", 24); Resume r2= (Resume)r1.clone() ; r2.setName("小李"); r2.setAge(30); r2.getWorkExperience().setCompanyName("公司B"); r2.getWorkExperience().setYears(3); System.out.println(r1.getName()+r1.getAge()+"岁,工作经验"+r1.getWorkExperience().getCompanyName()+","+r1.getWorkExperience().getYears()+"年"); System.out.println(r2.getName()+r2.getAge()+"岁,工作经验"+r2.getWorkExperience().getCompanyName()+","+r2.getWorkExperience().getYears()+"年"); } }
运行结果
小张24岁,工作经验公司B,3年 小李30岁,工作经验公司B,3年
简历r2修改工作经验后简历r1中的工作经验也同样被修改了。这是由于浅拷贝中关于引用的拷贝是只拷贝了应用地址,r1和r2中指向了相同的we引用。
深拷贝:
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。
工作经验类同样实现 Cloneable 接口
class WorkExperience implements Cloneable { private String companyName; private int years; public WorkExperience (String cname , int years ) { this.companyName = cname ; this.years = years; } public String getCompanyName() { return companyName; } public void setCompanyName(String companyName) { this.companyName = companyName; } public int getYears() { return years; } public void setYears(int years) { this.years = years; } public Object clone() { try { return super.clone(); //直接调用父类的clone方法 } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); return null ; } } }
简历类:简历类中的修改是通过拷贝设置工作经验
class Resume implements Cloneable { private WorkExperience workExperience ; private String name ; private int age ; public Resume(WorkExperience workExperience, String name, int age) { super(); this.workExperience = workExperience; this.name = name; this.age = age; } public WorkExperience getWorkExperience() { return workExperience; } public void setWorkExperience(WorkExperience workExperience) { this.workExperience = workExperience; } 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 Object clone() { Resume r = null; try { r= (Resume)super.clone(); r.setWorkExperience((WorkExperience)workExperience.clone()); //通过拷贝设置工作经验 return r; } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); return null ; } } }
运行测试:
同运行测试2中的代码相同
public class ProtoType { public static void main (String args[]) { WorkExperience we = new WorkExperience("公司A", 2); Resume r1 = new Resume(we, "小张", 24); Resume r2= (Resume)r1.clone() ; r2.setName("小李"); r2.setAge(30); r2.getWorkExperience().setCompanyName("公司B"); r2.getWorkExperience().setYears(3); System.out.println(r1.getName()+r1.getAge()+"岁,工作经验"+r1.getWorkExperience().getCompanyName()+","+r1.getWorkExperience().getYears()+"年"); System.out.println(r2.getName()+r2.getAge()+"岁,工作经验"+r2.getWorkExperience().getCompanyName()+","+r2.getWorkExperience().getYears()+"年"); } }
运行结果
小张24岁,工作经验公司A,2年 小李30岁,工作经验公司B,3年
r2修改工作经验后没有影响r1.
总结:
原型模式主要用到的技术就是克隆,这样如果是在创建对象比较费时是可以提高程序的效率;
深拷贝相对于浅拷贝来说要花费更多的内存开销,具体使用那种拷贝方式可以视情况而定;
深拷贝和浅拷贝可以结合使用(延迟拷贝)这样既可以提高效率也可以进行深拷贝。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。