设计模式
🗒️原型模式
00 min
2022-7-16
2023-7-31
type
status
date
slug
summary
tags
category
icon
password

原型模式

克隆羊问题

现在有一只羊tom,姓名为: tom,年龄为:1,颜色为:白色,请编写程序创建和tom羊 属性完全相同的10只羊。
notion image

传统方法优缺点:

  • 优点是比较好理解,简单易操作。
  • 在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低
  • 总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活
思路:Java中Object类是所有类的根类,Object类提供了一个clone()方法,该方法可以将一个Java对象复制一份,但是需要实现clone的Java类必须要实现一个接口Cloneable,该接口表示该类能够复制且具有复制的能力=>原型模式

原型模式

  • 原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
  • 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节
  • 工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它 们自己来实施创建,即 对象.clone()
notion image
原型模式的核心是就是原型类 Prototype,Prototype 类需要具备以下两个条件:
  • (1)实现 Cloneable 接口:在 Java 中 Cloneable 接口的作用就是在运行时通知虚拟机可以安全地在实现了 Cloneable 接口的类上使用 clone() 方法,只有在实现了 Cloneable 的类才可以被拷贝,否则在运行时会抛出 CloneNotSupportedException 异常。
  • (2)重写 Object 类中的 clone() 方法:Java 中所有类的父类都是 Object,Object 中有一个clone() 方法用于返回对象的拷贝,但是其作用域 protected,一般的类无法调用,因此,Prototype 类需要将 clone() 方法的作用域修改为 public。
原型模式是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式。在实际应用中,原型模式很少单独出现。经常与其他模式混用,他的原型类Prototype也常用抽象类来替代。

优点和适用场景

  1. 原型模式比 new 方式创建对象的性能要好的多,因为 Object 类的 clone() 方法是一个本地方法,直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显;
  1. 简化对象的创建;
  1. 原型模式适合在重复地创建相似对象的场景使用,比如在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且也可以提供系统的整体性能。

注意

  • 使用原型模式复制对象不会调用类的构造函数,对象是通过调用 Object 类的 clone() 方法来完成的,它直接在内存中复制数据。不但构造函数不会执行,甚至连访问权限都对原型模式无效。单例模式中,需要将构造函数的访问权限设置为 private,但是 clone() 方法直接无视构造方法的权限,所以单例模式与原型模式是冲突的,在使用时需要注意。
  • 深拷贝与浅拷贝。Object 类的 clone() 方法只会拷贝对象中的基本的数据类型(8种基本类型byte,char,short,int,long,float,double,boolean 和对应的封装类),对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

浅拷贝:

只克隆对象中的基本数据类型,而不会克隆数组、容器、引用对象等。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。如果变量为String字符串,则拷贝其引用地址,但是在修改的时候,它会从字符串池中重新生成一个新的字符串,原有的字符串对象保持不变。
  • 对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。
  • 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
  • 浅拷贝是使用默认的clone()方法来实现
  • sheep = (Sheep) super.clone();

深拷贝:

  • 复制对象的所有基本数据类型的成员变量值
  • 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝
  • 深拷贝实现方式1:重写clone方法来实现深拷贝
  • 深拷贝实现方式2:通过对象序列化实现深拷贝(推荐)
 
上一篇
工厂模式
下一篇
Netty之NIO基础