举个栗子

问题描述

要求有一个简历类,必须要有姓名,可以设置性别和年龄,可以设置工作经历,最终需要三份简历。

简单实现

简历类

/*** 简历类* Created by callmeDevil on 2019/7/13.*/
public class Resume {private String name;private String sex;private String age;private String timeArea;private String company;public Resume (String name) {this.name = name;}/*** 设置个人信息* @param sex* @param age*/public void setPersonalInfo(String sex, String age){this.sex = sex;this.age = age;}/*** 设置工作经历* @param timeArea* @param company*/public void setWorkExperience(String timeArea, String company) {this.timeArea = timeArea;this.company = company;}/*** 显示*/public void display () {System.out.println(String.format("%s %s %s", name, sex, age));System.out.println(String.format("工作经历:%s %s", timeArea, company));}// 此处省略get、set方法}

测试

/*** 测试* Created by callmeDevil on 2019/7/13.*/
public class Test {public static void main(String[] args) {Resume resumeA = new Resume("callmeDevil");resumeA.setPersonalInfo("男", "24");resumeA.setWorkExperience("2018-2019", "伟大的航道");Resume resumeB = new Resume("callmeDevil");resumeB.setPersonalInfo("男", "24");resumeB.setWorkExperience("2018-2019", "伟大的航道");Resume resumeC = new Resume("callmeDevil");resumeC.setPersonalInfo("男", "24");resumeC.setWorkExperience("2018-2019", "伟大的航道");resumeA.display();resumeB.display();resumeC.display();}}

测试结果

callmeDevil 男 24
工作经历:2018-2019 伟大的航道
callmeDevil 男 24
工作经历:2018-2019 伟大的航道
callmeDevil 男 24
工作经历:2018-2019 伟大的航道

存在的问题

跟手写简历没有差别,三份简历需要三份实例化,如果客户需要二十份简历,那就得实例化二十次。

原型模式

定义

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

UML图

代码实现

/*** 简历类(实现JDK克隆接口)* Created by callmeDevil on 2019/7/13.*/
public class Resume implements Cloneable{private String name;private String sex;private String age;private String timeArea;private String company;public Resume (String name) {this.name = name;}/*** 设置个人信息* @param sex* @param age*/public void setPersonalInfo(String sex, String age){this.sex = sex;this.age = age;}/*** 设置工作经历* @param timeArea* @param company*/public void setWorkExperience(String timeArea, String company) {this.timeArea = timeArea;this.company = company;}/*** 显示*/public void display () {System.out.println(String.format("%s %s %s", name, sex, age));System.out.println(String.format("工作经历:%s %s", timeArea, company));}/*** 实现克隆方法,可进行自己的克隆逻辑* @return* @throws CloneNotSupportedException*/@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}// 此处省略get、set方法}

测试

/*** 原型模式测试* Created by callmeDevil on 2019/7/13.*/
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Resume resumeA = new Resume("callmeDevil");resumeA.setPersonalInfo("男", "24");resumeA.setWorkExperience("2018-2019", "伟大的航道");// 只需要调用clone方法就可以实现新简历的生成,并且可以修改新简历的细节Resume resumeB = (Resume) resumeA.clone();resumeB.setWorkExperience("2019-2020", "新世界");Resume resumeC = (Resume) resumeA.clone();resumeC.setPersonalInfo("男", "25");resumeA.display();resumeB.display();resumeC.display();}}

测试结果

callmeDevil 男 24
工作经历:2018-2019 伟大的航道
callmeDevil 男 24
工作经历:2019-2020 新世界
callmeDevil 男 25
工作经历:2018-2019 伟大的航道

好处

  • 一般在初始化的信息不发生变化的情况下,克隆是最好的方法。这既隐藏了对象创建的细节,又对性能是大大的提高。
  • 不用重新初始化对象,而是动态的获得对象运行时的状态。

浅复制与深复制

浅复制

在上面这个简历类中,如果字段是值类型(基本数据类型)的,则对该字段直接进行复制;如果是引用类型(String等),则/复制引用/但不/复制引用的对象/;因此,原始对象及其副本引用同一对象。

在此之前,我们先做一个简单的测试

    System.out.println("123" == "123");System.out.println("123".equals("123"));System.out.println(new String("123") == new String("123"));System.out.println(new String("123").equals(new String("123")));

相信有点基础的都知道答案吧?就不卖弄了,直接上结果

true
true
false
true

至于结果为什么会这样,网上也许多分析,此处重点在浅复制的讲解,因此不做过多叙述。

带着上面的理解再看下面的内容。在可克隆的简历类例子中,基本数据类型就没什么好测试的,有兴趣的也可以将年龄改成 int 类型;对于其他 String 类型,就拿 company 字段来说,我们新建一个测试类看下是什么结果

public class Test2 {public static void main(String[] args) throws CloneNotSupportedException {Resume resumeA = new Resume("callmeDevil");resumeA.setWorkExperience("0", "伟大的航道");// 直接声明StringResume resumeB = (Resume) resumeA.clone();// A 与 B 的公司两种比较System.out.println(resumeA.getCompany() == resumeB.getCompany());System.out.println(resumeA.getCompany().equals(resumeB.getCompany()));resumeA.setWorkExperience("0", new String("伟大的航道"));//new 的方式创建StringResume resumeC = (Resume) resumeA.clone();// A 与 C 的公司两种比较System.out.println(resumeA.getCompany() == resumeC.getCompany());System.out.println(resumeA.getCompany().equals(resumeC.getCompany()));}}

比对第一个“123”的例子,稍微思考下在比对下面结果看是否一致

true
true
true
true

是的,这就是浅复制。不论A简历company直接声明的还是 new 出来的,在clone方法中都只会对 company 字段复制一份引用而已。因此才会出现 “==”“equal()”的结果都是“true”。对于引用类型来说,这个字段所在类实现了clone方法是不够的,它只会对引用类型复制一份引用,那如果连引用类型的字段也要创建一份新的数据,那便是 “深复制”

  • 浅复制就是,被复制的对象的所有变量都含有与原来对象相同的值,而所有其他对象的引用都仍然只想原来的对象。
  • 深复制把引用对象的变量指向复制过的新对象,而不是援用的被引用的对象。

深复制

此处不纠结于如何对上述 String 的深复制。现将简历类进行改造,把“工作经历”抽出成另一个类 WorkExperience

简历类2

/*** 简历类2(深复制)* Created by callmeDevil on 2019/7/13.*/
public class Resume2 implements Cloneable {private String name;private String sex;private String age;// 工作经历private WorkExperience work;public Resume2 (String name) {this.name = name;this.work = new WorkExperience();}private Resume2(WorkExperience work) throws CloneNotSupportedException {this.work = (WorkExperience) work.clone();}/*** 设置个人信息* @param sex* @param age*/public void setPersonalInfo(String sex, String age){this.sex = sex;this.age = age;}/*** 设置工作经历* @param timeArea* @param company*/public void setWorkExperience(String timeArea, String company) {// 此处赋值给 work 对象this.work.setWorkDate(timeArea);this.work.setCompany(company);}/*** 显示*/public void display () {System.out.println(String.format("%s %s %s", name, sex, age));// 此处显示 work 对象的值System.out.println(String.format("工作经历:%s %s", work.getWorkDate(), work.getCompany()));}/*** 实现克隆方法,可进行自己的克隆逻辑* @return* @throws CloneNotSupportedException*/@Overrideprotected Object clone() throws CloneNotSupportedException {// 调用私有的构造方法,让“工作经历”对象克隆完成,然后再给这个“简历”对象// 相关的字段赋值,最终返回一个深复制的简历对象Resume2 obj = new Resume2(this.work);obj.setName(this.name);obj.setSex(this.sex);obj.setAge(this.age);return obj;}// 此处省略get、set方法}

工作经历

/*** 工作经历* Created by callmeDevil on 2019/7/13.*/
public class WorkExperience implements Cloneable{private String workDate;private String company;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}// 此处省略get、set方法}

测试类

/*** 深复制测试* Created by callmeDevil on 2019/7/13.*/
public class TestDeepClone {public static void main(String[] args) throws CloneNotSupportedException {Resume2 resumeA = new Resume2("callmeDevil");resumeA.setPersonalInfo("男", "24");resumeA.setWorkExperience("2018-2019", "伟大的航道");Resume2 resumeB = (Resume2) resumeA.clone();resumeB.setWorkExperience("2019-2020", "新世界");Resume2 resumeC = (Resume2) resumeA.clone();resumeC.setWorkExperience("2020-XXXX", "木叶忍者村");resumeA.display();resumeB.display();resumeC.display();}}

测试结果

callmeDevil 男 24
工作经历:2018-2019 伟大的航道
callmeDevil 男 24
工作经历:2019-2020 新世界
callmeDevil 男 24
工作经历:2020-XXXX 木叶忍者村

可以看到,每次克隆都能将简历类中的工作经历类一同新建,而不是单纯的同个对象进行改变内容。如果是浅复制的实现,那么在相同测试类中会出现什么结果呢?应该能猜到吧,那就是三次输出都是一样的。
对于工作经历类浅复制实现本文就不描述了,有兴趣的可以自行测试,很简单,需要修改的地方有这么两处:

  • 简历类实现的克隆方法中直接调用 super.clone() 而不需要重写。
  • 取消工作经历类实现克隆接口及其方法。

只需要更改这两处,在相同的测试类中就能看到以下结果

callmeDevil 男 24
工作经历:2020-XXXX 木叶忍者村
callmeDevil 男 24
工作经历:2020-XXXX 木叶忍者村
callmeDevil 男 24
工作经历:2020-XXXX 木叶忍者村

看到此处就不需要解释了吧,每次克隆只是新实例化了“简历”,但三个“简历”中的“工作经历”都是同一个,每次 set值 的时候都必将影响到所有对象,所以输出的工作经历都是相同的。这也同时说明了实现深复制的必要条件

  • 需要实现深复制的引用类型字段的类(比如上文中的工作经历)必须实现 Cloneable 接口
  • 该字段的所属类(比如上文中的简历)实现的克隆方法中必须对该字段进行克隆与赋值

做到以上两点,即可将原本浅复制的功能转变为深复制

总结

原型模式无非就是对指定创建的原型实例进行复制,再对新对象另做操作,省去重新 new 的过程。其中复制便分为浅复制深复制

转载于:https://www.cnblogs.com/call-me-devil/p/11180403.html

大话设计模式笔记(七)の原型模式相关推荐

  1. 大话设计模式笔记 享元模式

    享元模式(Flyweigh),运用共享技术有效地支持大量细粒度的对象. package flyweight;//可以接受并作用于外部状态 public abstract class Flyweight ...

  2. Java描述设计模式(05):原型模式

    一.原型模式简介 1.基础概念 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象. 2.模式结构 原型模式要求对象实现一个 ...

  3. 大话设计模式读书笔记之原型模式

    由于大话这本书是以C#语言为基础写就的,本设计模式的例子中使用了一些c#中的API,因此就不再引用此书中的例子了,参考了一篇博客园中的大神写就的浅显易懂的JAVA版原型模式,在此奉上链接,以供大家学习 ...

  4. 大话设计模式读书笔记--6.原型模式

    简单的复制粘贴极有可能造成重复代码的灾难, 但是java中提供了克隆的功能, 如果一个对象创建过程复杂,又要频繁使用, 在初始化信息不发生变化的情况下,应当采取克隆而不是new一个对象 定义 原型模式 ...

  5. Java设计模式笔记——七个结构型模式

    系列文章目录 第一章 Java设计模式笔记--七大设计原则 第二章 Java设计模式笔记--六个创建型模式 文章目录 系列文章目录 一.适配器模式 1.概念 2.类适配器 3.对象适配 4.缺省适配器 ...

  6. 设计模式笔记七:桥接模式

    原文:http://www.runoob.com/design-pattern/ 少许个人理解,如有错误请指出.欢迎一起讨论. 同之前的原型模式,这一节菜鸟教程也比较抽象,仍然找一篇好懂的博客文章补充 ...

  7. 【设计模式学习笔记】原型模式

    原型模式,估计这是最简单的模式了.这个模式可以用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.额外说一句,这里的创建对象只是浅拷贝的. 文章目录 ...

  8. 【设计模式 06】原型模式(克隆??)

    原型模式(clone?) Prototype pattern refers to creating duplicate object while keeping performance in mind ...

  9. 大话设计模式之简单工厂模式

    一.简单工厂模式 1.起因 最近在看一本大话设计模式一书,感觉上面讲述的富有故事性,引导你一步一步的走进设计模式的世界.首先我先看到的是简单工厂模式,对此我想给自己做一个总结,给自己做一个提示. 2. ...

最新文章

  1. oracle导出超过100m的数据库,Oracle数据库的导出和导入
  2. POJ 3347 Kadj Squares(复杂的线段相交问题)
  3. web开发入门到深入-WebAssembly(1)
  4. 计算机仿真作业三,计算机仿真技术作业三.doc
  5. 注意职场“十不要”,让你少奋斗30年
  6. foreach语句的的解析
  7. 90.不用其它变量进行变量互换
  8. 12c闪回 oracle_Oracle 12c R2新特性: PDB级闪回(Flashback PDB)
  9. 这个机器人不学数据集,“纯玩”get各类家务技能,LeCun觉得很赞
  10. 写给新入职的毕业生们(二)
  11. 全部选中替换_一键解锁查找替换的新玩法!
  12. 编译XML-Parser报错
  13. 对讲机写频教程以(TCL-HT9为例)
  14. python 分类变量回归_虚拟/分类变量线性回归
  15. 华为HCNE考试练习题经典模拟题
  16. KMP --算法竞赛(33)
  17. 美团运筹优化实战——智能配送系统阅读笔记
  18. jsmap(桔色棉袄配什么颜色打底衫)
  19. 计算机毕业设计如何制作电子商务网站怎么制作购物网站计算机课程设计电子商城做什么(PHP-ASP.NET-c#-JavaWeb-SSM-SSH-J2EE-springBoot
  20. 独立游戏(一) 如何通过广告获取收益

热门文章

  1. 2022-2028中国工作服市场现状及未来发展趋势
  2. 记录一次简单、高效、无错误的linux上安装pytorch的过程
  3. 笔记本通过网线连接并控制工控机
  4. paddle一体安装
  5. linux下使用source /etc/profile保存配置后,新的环境变量只能在一个终端里面有效
  6. TensorFlow指定使用GPU 多块gpu
  7. Windows10+anaconda,python3.5, 安装glove-python
  8. vue响应式给数组中的对象添加新属性
  9. MindSpore模型推理
  10. Centos7 下安装VIM编辑器