Loading... # 设计模式(七)——原型模式 ## 参考 > 大话设计模式  ——  程杰 著 ## 目录 [设计模式(一)——简单工厂模式](https://www.princelei.club/archives/67.html) [设计模式(二)——策略模式](https://www.princelei.club/archives/68.html) [设计模式(三)——设计原则](https://www.princelei.club/archives/116.html) [设计模式(四)——装饰模式](https://www.princelei.club/archives/117.html) [设计模式(五)——代理模式](https://www.princelei.club/archives/119.html) [设计模式(六)——工厂方法模式](https://www.princelei.club/archives/132.html) [设计模式(七)——原型模式](https://www.princelei.club/archives/133.html) [设计模式(八)——模板方法模式](https://www.princelei.club/archives/134.html) [设计模式(九)——外观模式](https://www.princelei.club/archives/135.html) [设计模式(十)——建造者模式](https://www.princelei.club/archives/136.html) [设计模式(十一)——观察者模式](https://www.princelei.club/archives/137.html) [设计模式(十二)——抽象工厂模式](https://www.princelei.club/archives/138.html) [设计模式(十三)——状态模式](https://www.princelei.club/archives/139.html) [设计模式(十四)——适配器模式](https://www.princelei.club/archives/140.html) [设计模式(十五)——备忘录模式](https://www.princelei.club/archives/141.html) [设计模式(十六)——组合模式](https://www.princelei.club/archives/147.html) [设计模式(十七)——迭代器模式](https://www.princelei.club/archives/148.html) [设计模式(十八)——单例模式](https://www.princelei.club/archives/157.html) [设计模式(十九)——桥接模式](https://www.princelei.club/archives/159.html) [设计模式(二十)——命令模式](https://www.princelei.club/archives/160.html) [设计模式(二十一)——职责链模式](https://www.princelei.club/archives/161.html) [设计模式(二十二)——中介者模式](https://www.princelei.club/archives/162.html) [设计模式(二十三)——享元模式](https://www.princelei.club/archives/163.html) [设计模式(二十四)——解释器模式](https://www.princelei.club/archives/173.html) [设计模式(二十五)——访问者模式](https://www.princelei.club/archives/174.html) ## 何为原型模式 - 原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。 ## 原型模式实现简历的复制 ``` /** * 工作经历 */ 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 class Resume implements Cloneable { private String name; private String sex; private String age; private WorkExperience work; public Resume(String name) { this.name = name; work = new WorkExperience(); } //设置个人信息 public void setPersonalInfo(String sex, String age) { this.sex = sex; this.age = age; } //设置工作经历 public void setWorkExperience(String workDate, String company) { work.setWorkDate(workDate); work.setCompany(company); } //显示 public void display() { System.out.println(name + " " + sex + " " + age); System.out.println("工作经历 " + work.getWorkDate() + " " + work.getCompany()); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } ``` ``` /** * 客户端 */ public class MainClass { public static void main(String[] args) throws CloneNotSupportedException { Resume a = new Resume("大鸟"); a.setPersonalInfo("男","29"); a.setWorkExperience("1998-2000","XX公司"); Resume b = (Resume) a.clone(); b.setWorkExperience("1998-2000","XX公司"); Resume c = (Resume) a.clone(); c.setPersonalInfo("男","24"); c.setWorkExperience("1998-2000","XX公司"); a.display(); b.display(); c.display(); } } ``` 输出: ``` 大鸟 男 29 工作经历 1998-2000 XX公司 大鸟 男 29 工作经历 1998-2000 XX公司 大鸟 男 24 工作经历 1998-2000 XX公司 ``` 一般在初始化的信息不发生变化的情况下,克隆是最好的办法。既隐藏了对象创建的细节,又对性能大大提高,不用重新初始化对象,而是动态地获得对象运行时的状态。 ## 深复制与浅复制 默认的clone()方法是这样,如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其副本引用同一对象。 在上述程序中,若我客户端改成: ``` /** * 客户端 */ public class MainClass { public static void main(String[] args) throws CloneNotSupportedException { Resume a = new Resume("大鸟"); a.setPersonalInfo("男","29"); a.setWorkExperience("1998-2000","XX公司"); Resume b = (Resume) a.clone(); b.setWorkExperience("1998-2000","YY公司"); Resume c = (Resume) a.clone(); c.setPersonalInfo("男","24"); c.setWorkExperience("1998-2000","ZZ公司"); a.display(); b.display(); c.display(); } } ``` 结果: ``` 大鸟 男 29 工作经历 1998-2000 ZZ公司 大鸟 男 29 工作经历 1998-2000 ZZ公司 大鸟 男 24 工作经历 1998-2000 ZZ公司 ``` 因为WorkExperience为引用型,所以clone()复制的是引用,所以当设置公司为ZZ时,所有company值都会发生改变。这叫做‘浅复制’,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。而深复制是把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。深复制要深入到多少层,需要事先就考虑好,而且要当心出现循环引用的问题,需要小心处理,这里比较复杂,可以慢慢研究。 ## 简历的深复制实现 ``` /** * 工作经历 */ public class WorkExperience 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; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } ``` ``` /** * 简历 */ public class Resume implements Cloneable { private String name; private String sex; private String age; private WorkExperience work; public Resume(String name) { this.name = name; work = new WorkExperience(); } private Resume(WorkExperience work) throws CloneNotSupportedException { this.work = (WorkExperience) work.clone(); } //设置个人信息 public void setPersonalInfo(String sex, String age) { this.sex = sex; this.age = age; } //设置工作经历 public void setWorkExperience(String workDate, String company) { work.setWorkDate(workDate); work.setCompany(company); } //显示 public void display() { System.out.println(name + " " + sex + " " + age); System.out.println("工作经历 " + work.getWorkDate() + " " + work.getCompany()); } @Override protected Object clone() throws CloneNotSupportedException { Resume obj = new Resume(this.work); obj.name = this.name; obj.sex = this.sex; obj.age = this.age; return obj; } } ``` ``` /** * 客户端 */ public class MainClass { public static void main(String[] args) throws CloneNotSupportedException { Resume a = new Resume("大鸟"); a.setPersonalInfo("男","29"); a.setWorkExperience("1998-2000","XX公司"); Resume b = (Resume) a.clone(); b.setWorkExperience("1998-2000","YY公司"); Resume c = (Resume) a.clone(); c.setPersonalInfo("男","24"); c.setWorkExperience("1998-2000","ZZ公司"); a.display(); b.display(); c.display(); } } ``` 输出: ``` 大鸟 男 29 工作经历 1998-2000 XX公司 大鸟 男 29 工作经历 1998-2000 YY公司 大鸟 男 24 工作经历 1998-2000 ZZ公司 ``` Last modification:June 11th, 2020 at 06:26 pm © 允许规范转载