上期回顾:建造者模式

文章目录

  • 一、原型模式定义
  • 二、原型模式的结构与实现
  • 三、案例
    • (一)浅克隆
    • (二)深克隆
    • (三)浅克隆和深克隆的区别
  • 四、原型模式使用场景


一、原型模式定义

原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

二、原型模式的结构与实现

原型模式有以下三种角色:
1.抽象原型类(Prototype):规定了具体原型对象必须实现的接口。
2.具体原型类(Realizetype):实现抽象原型类的 clone() 方法,它是可被复制的对象。
3.访问类(PrototypeTest):使用具体原型类中的 clone() 方法来复制新的对象

原型模式的克隆可以分为浅克隆深克隆

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

Java中的Object类中提供clone()方法来实现浅克隆。Cloneable接口就是抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。

原型模式设计如下:

//在这里抽象原型类是Cloneable接口
//具体原型类
public class Realizetype implements Cloneable{public Realizetype() {System.out.println("具体原型对象已创建成功!");}@Overrideprotected Realizetype clone() throws CloneNotSupportedException {System.out.println("具体原型已复制成功!");return (Realizetype) super.clone();}
}
//访问类
public class Client {public static void main(String[] args) throws CloneNotSupportedException {//创建一个原型类对象Realizetype realizetype = new Realizetype();//得到原型对象的克隆对象Realizetype clone = realizetype.clone();//查看是否是同一个对象System.out.println("原型对象和克隆的对象是否是同一个对象:"+(realizetype == clone));}
}

测试结果:
具体原型对象已创建成功!
具体原型已复制成功!
原型对象和克隆的对象是否是同一个对象:false

这里展示的原型模式只是一个简单的克隆,抽象原型类就是Cloneable接口具体原型类就是可被复制的对象,而访问类就是使用克隆clone()来复制新的对象

需要注意的是,单看测试结果我们会发现原型模式有以下几个问题。

  • 克隆底层不是通过new对象实现的,因为调用clone()的时候并没有打印出Realizetype 类的构造函数中的内容。
  • 原型对象和克隆的对象不是同一个对象

而且查看clone()源码发现它是一个native本地方法,也是说它并不是由java语言实现的。

 protected native Object clone() throws CloneNotSupportedException;

三、案例

用原型模式来实现以下需求:
假如某学校要对这一学期的社团指导老师颁发聘书,那么我现在就可以根据奖状模板进行克隆,用原型模式设计思想实现。

原型对象:奖状类

//原型对象:聘书
public class Letter implements Cloneable{private String name;  //指导老师姓名public String getName() {return name;}public void setName(String name) {this.name = name;}public void show(){System.out.println("兹聘请 "+name+" 老师为 xxx 社团指导老师!");}@Overrideprotected Letter clone() throws CloneNotSupportedException {return (Letter)super.clone();}
}

访问类:测试

public class Test {public static void main(String[] args) throws CloneNotSupportedException {Letter letter = new Letter();//开始克隆Letter letter1 = letter.clone();//原型对象System.out.print("原型对象:");letter.setName("张三");letter.show();//克隆对象System.out.print("克隆后对象:");letter1.setName("李四");letter1.show();}
}

运行结果:

原型对象: 兹聘请 张三 老师为 xxx 社团指导老师!
克隆后对象: 兹聘请 李四 老师为 xxx 社团指导老师!

这个例子比较简单好理解,现在我在这个案例中引入深克隆和浅克隆的概念。

(一)浅克隆

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

1、首先我再创建一个社团类,里面有一个社团名称的属性

//社团类
public class Association {private String name ;  //社团名称public Association(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

2、修改聘书类,加上一个社团类的对象属性

//原型对象:聘书
public class Letter implements Cloneable{private String name;  //指导老师姓名private Association association;  //社团public Letter(String name, Association association) {this.name = name;this.association = association;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Association getAssociation() {return association;}public void setAssociation(Association association) {this.association = association;}public void show(){System.out.println("兹聘请 "+name+" 老师为 "+association.getName()+" 社团指导老师!");}@Overrideprotected Letter clone() throws CloneNotSupportedException {return (Letter)super.clone();}
}

测试类:将原型对象聘书类进行克隆,然后打印出原型对象中Association引用地址和克隆后Association引用地址,判断该引用地址是否发生改变

public class Test {public static void main(String[] args) throws CloneNotSupportedException {Association association = new Association("歌舞社");//拷贝之前的对象Letter letter = new Letter("张三",association);System.out.print("克隆前对象:");letter.show();//拷贝之后的对象Letter letter1 = letter.clone();System.out.print("克隆后对象:");letter1.show();//判断System.out.println(letter.getAssociation() == letter1.getAssociation());System.out.println("克隆前Association对象的hashCode:"+letter.getAssociation().hashCode());System.out.println("克隆后Association对象的hashCode:"+letter1.getAssociation().hashCode());}
}

输出结果:

克隆前对象:兹聘请 张三 老师为 歌舞社 社团指导老师!
克隆后对象:兹聘请 张三 老师为 歌舞社 社团指导老师!
true
克隆前Association对象的hashCode:666988784
克隆后Association对象的hashCode:666988784

结果发现,letter.getAssociation() == letter1.getAssociation()结果返回true,说明克隆前后Letter类中持有的Association引用地址没有发生改变,加上show()内容一样,说明属性也没发生改变,这明显符合我们对浅克隆的定义。而且打印出来的hashCode值相同,同样证明了它们是引用的同一个地址。

由于指向同一个地址,那我对克隆后的对象修改属性,原来的原型对象中的属性也会发生变化吗?
测试如下,将克隆的对象中原来的张三指导的“歌舞社”改为“足球社”,再查看未克隆前的原型对象是否发生了改变。

public class Test {public static void main(String[] args) throws CloneNotSupportedException {Association association = new Association("歌舞社");Letter letter = new Letter("张三",association);//原来System.out.println("原对象:");letter.show();//克隆并修改Letter clone = letter.clone();Association association1 = clone.getAssociation();association1.setName("足球社");//再次查看原来对象System.out.println("克隆对象修改后再次查看原来对象:");letter.show();}
}

测试结果:

原对象:
兹聘请 张三 老师为 歌舞社 社团指导老师!

克隆对象修改后再次查看原来对象:
兹聘请 张三 老师为 足球社 社团指导老师!

发现修改克隆对象中的属性,原对象也发生了同步改变。这再一次说明了浅克隆中,会把原型对象中成员变量为引用类型的引用地址也复制给克隆对象,且此引用对象的地址是共享给原型对象和克隆对象的。

总结:浅克隆只复制指向某个对象的引用,而不复制对象本身,新旧对象还是共享同一块内存,修改对象会改到原对象

(二)深克隆

清楚了浅克隆例子后。再来回顾一下深克隆的定义 ---- 创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

这要如何实现?很简单>

让Association类实现Cloneable接口,重写clone()方法

@Override
protected Association clone() throws CloneNotSupportedException {return (Association) super.clone();
}

修改Letter类的clone()方法,加上对association的克隆

@Override
protected Letter clone() throws CloneNotSupportedException {Letter letter = (Letter)super.clone();//拷贝Association对象letter.association= this.association.clone();return letter;
}

测试结果:

原对象:
兹聘请 张三 老师为 歌舞社 社团指导老师!

克隆后对象:
兹聘请 张三 老师为 足球社 社团指导老师!

克隆对象修改后再次查看原来对象:
兹聘请 张三 老师为 歌舞社 社团指导老师!

经过这一顿操作后,修改克隆后对象的属性,也不会影响到原对象,这就是深克隆,它将原型对象中的所有类型,无论是值类型还是引用类型,都复制了一份给克隆对象。

总结:深克隆对原型对象完全拷贝,但新对象跟原对象不共享内存,修改新对象不会改变原对象。

(三)浅克隆和深克隆的区别

最后用一张图简单的总结一下浅克隆和深克隆的区别

四、原型模式使用场景

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

它的使用场景如下:

1、资源优化场景。
2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
3、性能和安全要求的场景。
4、通过new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
5、一个对象多个修改者的场景。
6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

原型模式(深克隆、浅克隆)相关推荐

  1. 原型模式(浅克隆、深克隆)

    浅克隆: 值的传递,应用的传递(克隆的对象的引用是一致的,所以多个应用指向的是同一个对象,修改一个引用的对象,其他对象也会收到影响(牵一发而动全身)) 深克隆: 对于基本数据类型也是值的传递,对于引用 ...

  2. 原型模式【浅克隆实现,使用序列化实现深克隆】Java代码演示

    文章目录 原型模式 浅克隆 深克隆(使用序列化) 原型模式 原型模式(Prototype) 的定义如下: 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象. 在这里, ...

  3. 创建型设计模式-----原型模式(浅克隆、深克隆)

    目录 简介 为什么用克隆 浅克隆 深克隆 序列化实现深拷贝 应用场景 今天讲创建型设计模式中的原型模式,大家可以从标题中略微猜测一下,这个原型模式是个什么东东. 简介 定义:用原型实例创建对象的种类, ...

  4. Java设计模式之原型模式(浅克隆,深克隆)

    一.原型模式: 概述: 创建型模式之一,它通过复制一个已有对象来获取更多相同或相似的对象,可提高对象创建效率,简化创建过程. 原理: 将一个原型对象传给要发动创建的对象(如客户端对象),这个客户端对象 ...

  5. 原型模式以及深克隆和浅克隆

    原型模式的好处 创建比较复杂的对象,无需考虑过程,简化了创建对象的创建过程,同时也能提 高效率 原型模式分为浅克隆和深克隆,不同点 以我目前的理解:深克隆和浅克隆对于我们对象内的引用对象的克隆不一样 ...

  6. 原型模式 java 深浅_java学习笔记之原型模式及深浅拷贝

    一.原型模式的基本介绍 在聊原型模式之前,我们来思考一个小问题,传统的方式我们是如何克隆对象呢? 那我们以多利羊(Sheep)为例,来说明上述这个问题,具体代码见下面: 多利羊(Sheep) publ ...

  7. 《23种设计模式之原型模式(2种实现)》

    说在前头:本人为大二在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,能力有限,文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正.若 ...

  8. Java原型模式(prototype)

      prototype模式也就是原型模式,是javaGOF23种设计模式中的一种,我们在学习spring的时候在bean标签的学习中碰到过,所以本文来给大家介绍下原型模式 原型模式   在java中我 ...

  9. 原型模式——浅克隆和深克隆

    概述 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象. 结构 原型模式包含如下角色: 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法. 具体原型类: ...

  10. 原型模式,也叫克隆、拷贝模式,深克隆浅克隆

    概念: * 原型模式:也可以说是克隆模式.* 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以用原型模式.* 就是java的克隆技术,以某个对象为原型,复制出新的对象,显然,新的对象具备 ...

最新文章

  1. C语言初学者代码中的常见错误与瑕疵(2)
  2. 双显卡能双屏显示吗_i5-8305G+双显卡交火,最近很火的迷你主机零刻Turbo性能靠谱吗?...
  3. 多进程实现生产者消费者
  4. 魔兽世界客户端数据研究(三)
  5. Ajax学习总结+案例
  6. 第 4 章 设计模式概述
  7. 这款工具不用手写一行代码就能做出网站!
  8. #PYTHON#数据模型
  9. 工具推荐:三款自动化代码审计工具
  10. 【致远FAQ】A6+Cloud__V1.0_A6+cloud的M3端地址保存提示:not found
  11. Excel quot;定位条件quot;使用技巧(1)快速在空格,批量写入公式。
  12. 读书笔记:聪明人用方格纸
  13. SIM7600CE模块(GSM/GPRS)调试
  14. 游戏服务器开发环境搭建
  15. 【AWS】一、如何在AWS免费撸一年的服务器
  16. Robotstudio 获取机器人D-H参数
  17. yui2 datatable转换至yui3
  18. Itunes制作手机铃声,图文版
  19. 全国道路运证基本信息查询服务器,道路运政管理信息系统.doc
  20. java 框架 面试常见题目

热门文章

  1. 2021年考研经验分享(初试408分)
  2. 一例智能网卡(mellanox)的网卡故障分析
  3. 【读书笔记】《有效需求分析》
  4. NVIDIA-CUDA编程初探
  5. OpenCV实现同态滤波
  6. 开闭原则应用-书店打折Java代码实现
  7. 电脑连接西门子S7-200CPU的步骤
  8. ssm的餐饮点餐系统源码
  9. xsd文件规则和语法
  10. ARM指令集与Thumb指令集与Thumb-2指令集的区别