0、使用场景

(1)类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
(2)通过new一个对象需要非常繁琐的数据准备或访问权限,可以使用原型模式。
(3)一个对象需要提供给其他对象访问,而且各个调用者可能需要修改其值,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝

一、需求案例

现在有一只羊tom,姓名为tom,年龄为1,颜色为白色,编写冲虚创建和tom羊属性完全相同的十只羊。

(1)传统方式

new一个羊,get到tom的属性,然后set到新new的羊里

优缺点:

image.png

二、原型模式基本介绍

image.png
image.png

(1)原型模式改进克隆羊问题

1、类实现Cloneable接口

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class Sheep implements Cloneable{
  5. private String name;
  6. private String color;
  7. // 实现Cloneable接口的clone方法
  8. // 克隆该实例,直接调用父类的方法克隆(因此是浅拷贝,如果要实现深拷贝,要重写该方法)
  9. // 这里是浅拷贝
  10. @Override
  11. protected Sheep clone() throws CloneNotSupportedException {
  12. Sheep sheep = null;
  13. try {
  14. sheep = (Sheep) super.clone();
  15. } catch (Exception e) {
  16. System.out.println(e.getMessage());
  17. }
  18. return sheep;
  19. }
  20. }

2、测试

  1. public class PrototypeTest {
  2. public static void main(String[] args) throws CloneNotSupportedException {
  3. Sheep sheep = new Sheep("tom", "白色");
  4. Sheep sheep1 = sheep.clone();
  5. System.out.println(sheep == sheep1); // false
  6. System.out.println(sheep.equals(sheep1)); // true
  7. }
  8. }

三、浅拷贝与深拷贝

(1)浅拷贝

image.png

(2)深拷贝

image.png

(3)重写clone方法实现深拷贝

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class SheepOfDeepCopy implements Cloneable, Serializable {
  5. private static final long UID = 1L;
  6. private String name;
  7. private String color;
  8. private Sheep sheep;
  9. // 方式一:重写clone方法实现深拷贝
  10. @Override
  11. protected SheepOfDeepCopy clone() throws CloneNotSupportedException {
  12. SheepOfDeepCopy sheepOfDeepCopy = null;
  13. try {
  14. // 完成对基本数据类型和String类型的克隆
  15. sheepOfDeepCopy = (SheepOfDeepCopy) super.clone();
  16. // 对引用类型的属性,进行单独的处理
  17. // 即Sheep也要实现Cloneable接口的clone方法
  18. sheepOfDeepCopy.sheep = sheep.clone();
  19. } catch (Exception e) {
  20. System.out.println(e.getMessage());
  21. }
  22. return sheepOfDeepCopy;
  23. }
  24. }
  1. public class SheepOfDeepCopyTest {
  2. public static void main(String[] args) throws CloneNotSupportedException {
  3. Sheep sheep = new Sheep("tom", "白色");
  4. SheepOfDeepCopy sheepOfDeepCopy = new SheepOfDeepCopy("zjl", "粉色", sheep);
  5. SheepOfDeepCopy sheepOfDeepCopy1 = sheepOfDeepCopy.clone();
  6. System.out.println(sheepOfDeepCopy == sheepOfDeepCopy1); // false
  7. System.out.println(sheepOfDeepCopy.equals(sheepOfDeepCopy1)); // true
  8. System.out.println(sheepOfDeepCopy.getSheep() == sheepOfDeepCopy1.getSheep()); // false
  9. System.out.println(sheepOfDeepCopy.getSheep().equals(sheepOfDeepCopy1.getSheep())); // true
  10. }
  11. }

缺点:如果一个类中引用类型很多,那就很麻烦,因为这个类引用的所有类都要实现Cloneable接口。而且仔细想想,这好像还是浅拷贝

(4)通过对象序列化实现深拷贝(推荐)

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class SheepOfDeepCopy implements Serializable {
  5. private static final long UID = 1L;
  6. private String name;
  7. private String color;
  8. private Sheep sheep;
  9. // 用此种方式其引用类型一定要实现SerializationClone接口,否则报错
  10. public SheepOfDeepCopy SerializationClone() {
  11. // 因为要序列化,所有先创建流对象
  12. ByteArrayOutputStream bos;
  13. ObjectOutputStream oos;
  14. ByteArrayInputStream bis;
  15. ObjectInputStream ois;
  16. try {
  17. // 序列化
  18. bos = new ByteArrayOutputStream();
  19. oos = new ObjectOutputStream(bos);
  20. // 将当前对象以对象流的方式输出
  21. oos.writeObject(this);
  22. // 反序列化
  23. bis = new ByteArrayInputStream(bos.toByteArray());
  24. ois = new ObjectInputStream(bis);
  25. SheepOfDeepCopy sheepOfDeepCopy = (SheepOfDeepCopy) ois.readObject();
  26. return sheepOfDeepCopy;
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. return null;
  30. } finally {
  31. // 关闭流操作
  32. // TODO try-with-resource
  33. }
  34. }
  35. }

优化:使用try-with-resource替换try-catch-finally

基本介绍:
try-with-resources语句是一种声明了一种或多种资源的try语句。资源是指在程序用完了之后必须要关闭的对象。try-with-resources语句保证了每个声明了的资源在语句结束的时候都会被关闭。任何实现了java.lang.AutoCloseable接口的对象,和实现了java.io.Closeable接口的对象,都可以当做资源使用。

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class SheepOfDeepCopy implements Serializable {
  5. private static final long UID = 1L;
  6. private String name;
  7. private String color;
  8. private Sheep sheep;
  9. // 用此种方式其引用类型一定要实现SerializationClone接口,否则报错
  10. public SheepOfDeepCopy SerializationClone() {
  11. try (
  12. // 因为要序列化,所有先创建流对象
  13. // 序列化
  14. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  15. ObjectOutputStream oos = new ObjectOutputStream(bos);
  16. // 反序列化
  17. ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  18. ObjectInputStream ois = new ObjectInputStream(bis);
  19. ) {
  20. SheepOfDeepCopy sheepOfDeepCopy = (SheepOfDeepCopy) ois.readObject();
  21. return sheepOfDeepCopy;
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. return null;
  25. }
  26. }
  27. }

总结

image.png