大话设计模式之原型模式
原型模式
是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。
浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
具体实现
原型类
package com.chenpt.designModel.prototypeModel; import java.io.Serializable; /** * @Author: chenpengtao * @Description: 简历 * @Date: created in 2018/8/1 * @Modified By: */ public class Resume implements Cloneable,Serializable{ private static final long serialVersionUID = 1L; private String name; private String sex; private String age; Resume(String name,String sex,String age){ this.name=name; this.sex=sex; this.age=age; } /** * 设置个人信息 * @param sex * @param age */ public void setPersonInfo(String sex,String age){ this.sex=sex; this.age=age; } //描述 public void dispaly(){ System.out.println("姓名:"+name+"\t年龄:"+age+"\t性别:"+sex); } public Object clone(){ try { Resume resume = (Resume)super.clone(); return resume; }catch (Exception e){ return null; } } }
客户端
package com.chenpt.designModel.prototypeModel; /** * @Author: chenpengtao * @Description: * @Date: created in 2018/8/1 * @Modified By: */ public class MainTest { public static void main(String[] args){ Resume resume = new Resume("大鸟","男","25"); Resume resume2 = (Resume)resume.clone(); resume2.setPersonInfo("男","26"); resume.dispaly(); resume2.dispaly(); } } //结果 姓名:大鸟 年龄:25 性别:男 姓名:大鸟 年龄:26 性别:男
如上代码基本实现了一个原型模式示例:
浅复制与深复制
现在需求改了--我们需要新加入工作经历,那么修改上述代码
新加入工作类
package com.chenpt.designModel.prototypeModel; /** * @Author: chenpengtao * @Description: 工作经历 * @Date: created in 2018/8/1 * @Modified By: */ public class WorkExperience{ private String workDate; private String company; public WorkExperience(String workDate,String company){ this.workDate=workDate; this.company=company; } public WorkExperience(){} 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; } }
在个人信息那边引入工作类
package com.chenpt.designModel.prototypeModel; import java.io.Serializable; /** * @Author: chenpengtao * @Description: 简历 * @Date: created in 2018/8/1 * @Modified By: */ public class Resume implements Cloneable,Serializable{ private static final long serialVersionUID = 1L; private String name; private String sex; private String age; private WorkExperience workExperience; Resume(String name,String sex,String age){ this.name=name; this.sex=sex; this.age=age; this.workExperience=new WorkExperience(); } /** * 设置个人信息 * @param sex * @param age */ public void setPersonInfo(String sex,String age){ this.sex=sex; this.age=age; } /** * 设置工作经历 * @param workDate * @param company */ public void setWorkExperience(String workDate, String company){ this.workExperience.setWorkDate(workDate); this.workExperience.setCompany(company); } //描述 public void dispaly(){ System.out.println("姓名:"+name+"\t年龄:"+age+"\t性别:"+sex); System.out.println("工作经历:"+workExperience.getWorkDate()+"\t"+workExperience.getCompany()); } public Object clone(){ try { Resume resume = (Resume)super.clone(); return resume; }catch (Exception e){ return null; } } }
客户端
package com.chenpt.designModel.prototypeModel; /** * @Author: chenpengtao * @Description: * @Date: created in 2018/8/1 * @Modified By: */ public class MainTest { public static void main(String[] args){ Resume resume = new Resume("大鸟","男","25"); resume.setWorkExperience("2015-2016","南京工作"); Resume resume2 = (Resume)resume.clone(); resume2.setPersonInfo("男","26"); resume2.setWorkExperience("2016-2018","上海工作"); resume.dispaly(); resume2.dispaly(); } } //执行结果 姓名:大鸟 年龄:25 性别:男 工作经历:2016-2018 上海工作 姓名:大鸟 年龄:26 性别:男 工作经历:2016-2018 上海工作
咦!!!什么情况???怎么工作经历显示的是最后一次设置的值啊?
不要慌 问题不大。这是由于浅表复制导致的结果,对于值类型 克隆没问题,但对于引用类型来说,就只是复制了引用,引用的对象还是原来对象的地址,所以才有上述结果,既然已经说到这了就介绍下浅复制和深复制的概念吧
浅复制:被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象是引用都仍然指向原来的对象。
深复制:就是把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
深复制演示示例
修改工作经历实现克隆
package com.chenpt.designModel.prototypeModel; /** * @Author: chenpengtao * @Description: 工作经历 * @Date: created in 2018/8/1 * @Modified By: */ public class WorkExperience implements Cloneable{ private String workDate; private String company; public WorkExperience(String workDate,String company){ this.workDate=workDate; this.company=company; } public WorkExperience(){} 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 Object clone(){ try { return super.clone(); }catch (Exception e){ return null; } } }
修改resume对象
package com.chenpt.designModel.prototypeModel; import java.io.Serializable; /** * @Author: chenpengtao * @Description: 简历 * @Date: created in 2018/8/1 * @Modified By: */ public class Resume implements Cloneable,Serializable{ private static final long serialVersionUID = 1L; private String name; private String sex; private String age; private WorkExperience workExperience; Resume(String name,String sex,String age){ this.name=name; this.sex=sex; this.age=age; this.workExperience=new WorkExperience(); } /** * 添加私有构造 克隆工作经历 * @param workExperience */ private Resume(WorkExperience workExperience){ this.workExperience= (WorkExperience) workExperience.clone(); } /** * 设置个人信息 * @param sex * @param age */ public void setPersonInfo(String sex,String age){ this.sex=sex; this.age=age; } /** * 设置工作经历 * @param workDate * @param company */ public void setWorkExperience(String workDate, String company){ this.workExperience.setWorkDate(workDate); this.workExperience.setCompany(company); } //描述 public void dispaly(){ System.out.println("姓名:"+name+"\t年龄:"+age+"\t性别:"+sex); System.out.println("工作经历:"+workExperience.getWorkDate()+"\t"+workExperience.getCompany()); } /** * 重写了克隆方法 * @return */ public Object clone(){ try { Resume resume = new Resume(this.workExperience);//调用私有构造器实现工作经历克隆 //给对象属性重新赋值--最终返回的是深复制的resume对象 resume.name=this.name; resume.sex=this.sex; resume.age=this.age; return resume; }catch (Exception e){ return null; } } }
客户端
package com.chenpt.designModel.prototypeModel; /** * @Author: chenpengtao * @Description: * @Date: created in 2018/8/1 * @Modified By: */ public class MainTest { public static void main(String[] args){ Resume resume = new Resume("大鸟","男","25"); resume.setWorkExperience("2015-2016","南京工作"); Resume resume2 = (Resume)resume.clone(); resume2.setPersonInfo("男","26"); resume2.setWorkExperience("2016-2018","上海工作"); resume.dispaly(); resume2.dispaly(); } } //执行结果 姓名:大鸟 年龄:25 性别:男 工作经历:2015-2016 南京工作 姓名:大鸟 年龄:26 性别:男 工作经历:2016-2018 上海工作