基本需求:
- 有一个Sheep类的对象,我们现在需要创建100个和该对象属性完全一致的对象
传统方式:
-
代码实现
-
// Sheep类 @Data @ToString @NoArgsConstructor @AllArgsConstructor public class Sheep { private String name; private int age; } // Client public static void main(String[] args) { Sheep sheep = new Sheep("zhangsan",20); // 传统方式 Sheep sheep1 = new Sheep(sheep.getName(),sheep.getAge()); // ...... System.out.println(sheep1); }
-
-
缺陷及改进
基本介绍:
-
创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用
-
实现方式:实现Cloneable接口,复写clone()方法或通过序列化,原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口
-
优缺点:
-
使用场景:
-
UMl类图
-
代码实现
-
@Data @ToString @NoArgsConstructor @AllArgsConstructor public class Sheep implements Serializable,Cloneable { private String name; private int age; // 默认的super.clone()实现的浅拷贝,即对于基本类型和字符串拷贝直接赋值,对于引用类型的直接拷贝的引用(并没有重新创建该内部的对象) private Friend friend; @Override protected Object clone() throws CloneNotSupportedException { // 如果没有实现Cloneable接口 调用该方法会抛出CloneNotSupportedException异常 return super.clone(); } } public class Client { public static void main(String[] args) throws CloneNotSupportedException { Friend friend = new Friend("666"); Sheep sheep = new Sheep("zhangsan",23,friend); // 使用默认clone方法 采用的是浅拷贝 Sheep sheep1 = (Sheep) sheep.clone(); Sheep sheep2 = (Sheep) sheep.clone(); System.out.println(sheep1.toString()); System.out.println(sheep2.toString()); // 结果是true 说明clone出来的sheep1和sheep2中引用的是同一Friend对象,并没有将Friend对象再克隆一份,是浅拷贝 // 深拷贝则是将Friend对象再克隆一份,sheep1和sheep2中引用的不是同一Friend对象 结果为false System.out.println(sheep1.getFriend() == sheep2.getFriend()); } }
-
spring源码:
-
在spring中Abstractbeanfactory类中doGetBean()方法中有使用到原型模式,配置bean标签时,有个属性为Scope
-
if (mbd.isSingleton()) { sharedInstance = this.getSingleton(beanName,() -> { try { return this.createBean(beanName,mbd,args); } catch (BeansException var5) { this.destroySingleton(beanName); throw var5; } }); bean = this.getObjectForBeanInstance(sharedInstance,name,beanName,mbd); // 此处判断了是否使用了prototype } else if (mbd.isPrototype()) { var11 = null; Object prototypeInstance; try { this.beforePrototypeCreation(beanName); prototypeInstance = this.createBean(beanName,args); } finally { this.afterPrototypeCreation(beanName); } }
-
浅拷贝和深拷贝:
-
默认的super.clone()实现的浅拷贝,即对于基本类型和字符串拷贝直接赋值,对于引用类型的直接拷贝的引用(并没有重新创建该内部的对象)
-
深拷贝则是将对象内部引用类型的属性会创建新的对象,使用的不是同一个对象
-
深拷贝实现方式
- 重写clone()方法,需要实现Cloneable接口
- 使用序列化,需要实Serializable
-
代码实现
-
// Sheep 类 重写clone方法 和 增加deepClone方法 @Data @ToString @NoArgsConstructor @AllArgsConstructor public class Sheep implements Serializable,Cloneable { private String name; private int age; // 默认的super.clone()实现的浅拷贝,即对于基本类型和字符串拷贝直接赋值,对于引用类型的直接拷贝的引用(并没有重新创建该内部的对象) private Friend friend; @Override protected Object clone() throws CloneNotSupportedException { // 如果没有实现Cloneable接口 调用该方法会抛出CloneNotSupportedException异常 // return super.clone(); // 实现深拷贝方式一 重写clone方法 此种方法不好用 // 如果最外层对象有多个引用类型的属性,则每个引用属性都要进行克隆,很麻烦 // 如果层对象内部引用类型的属性仍然有引用类型的属性,则需要多层克隆,不易实现 // 1.先浅拷贝最外层的对象 Sheep sheep = (Sheep) super.clone(); // 2.再拷贝外层对象内部引用类型的属性 if (null != sheep.getFriend()) { sheep.setFriend((Friend) sheep.getFriend().clone()); } return sheep; } public Object deepClone() { // 实现深拷贝方式二 序列化方式 ByteArrayOutputStream byteArrayOutputStream = null; ObjectOutputStream objectOutputStream = null; ByteArrayInputStream byteArrayInputStream = null; ObjectInputStream objectInputStream = null; try { byteArrayOutputStream = new ByteArrayOutputStream(); objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); // 将当前对象写入到字节数组流中 objectOutputStream.writeObject(this); byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); objectInputStream = new ObjectInputStream(byteArrayInputStream); // 从字节数组流中读取对象并返回 return (Sheep) objectInputStream.readObject(); } catch (Exception e) { e.printStackTrace(); return null; } finally { try { objectInputStream.close(); byteArrayInputStream.close(); objectOutputStream.close(); byteArrayOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }