0、使用场景
(1)类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
(2)通过new一个对象需要非常繁琐的数据准备或访问权限,可以使用原型模式。
(3)一个对象需要提供给其他对象访问,而且各个调用者可能需要修改其值,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝
一、需求案例
现在有一只羊tom,姓名为tom,年龄为1,颜色为白色,编写冲虚创建和tom羊属性完全相同的十只羊。
(1)传统方式
new一个羊,get到tom的属性,然后set到新new的羊里
优缺点:
二、原型模式基本介绍
(1)原型模式改进克隆羊问题
1、类实现Cloneable接口
@Data@AllArgsConstructor@NoArgsConstructorpublic class Sheep implements Cloneable{private String name;private String color;// 实现Cloneable接口的clone方法// 克隆该实例,直接调用父类的方法克隆(因此是浅拷贝,如果要实现深拷贝,要重写该方法)// 这里是浅拷贝@Overrideprotected Sheep clone() throws CloneNotSupportedException {Sheep sheep = null;try {sheep = (Sheep) super.clone();} catch (Exception e) {System.out.println(e.getMessage());}return sheep;}}
2、测试
public class PrototypeTest {public static void main(String[] args) throws CloneNotSupportedException {Sheep sheep = new Sheep("tom", "白色");Sheep sheep1 = sheep.clone();System.out.println(sheep == sheep1); // falseSystem.out.println(sheep.equals(sheep1)); // true}}
三、浅拷贝与深拷贝
(1)浅拷贝
(2)深拷贝
(3)重写clone方法实现深拷贝
@Data@AllArgsConstructor@NoArgsConstructorpublic class SheepOfDeepCopy implements Cloneable, Serializable {private static final long UID = 1L;private String name;private String color;private Sheep sheep;// 方式一:重写clone方法实现深拷贝@Overrideprotected SheepOfDeepCopy clone() throws CloneNotSupportedException {SheepOfDeepCopy sheepOfDeepCopy = null;try {// 完成对基本数据类型和String类型的克隆sheepOfDeepCopy = (SheepOfDeepCopy) super.clone();// 对引用类型的属性,进行单独的处理// 即Sheep也要实现Cloneable接口的clone方法sheepOfDeepCopy.sheep = sheep.clone();} catch (Exception e) {System.out.println(e.getMessage());}return sheepOfDeepCopy;}}
public class SheepOfDeepCopyTest {public static void main(String[] args) throws CloneNotSupportedException {Sheep sheep = new Sheep("tom", "白色");SheepOfDeepCopy sheepOfDeepCopy = new SheepOfDeepCopy("zjl", "粉色", sheep);SheepOfDeepCopy sheepOfDeepCopy1 = sheepOfDeepCopy.clone();System.out.println(sheepOfDeepCopy == sheepOfDeepCopy1); // falseSystem.out.println(sheepOfDeepCopy.equals(sheepOfDeepCopy1)); // trueSystem.out.println(sheepOfDeepCopy.getSheep() == sheepOfDeepCopy1.getSheep()); // falseSystem.out.println(sheepOfDeepCopy.getSheep().equals(sheepOfDeepCopy1.getSheep())); // true}}
缺点:如果一个类中引用类型很多,那就很麻烦,因为这个类引用的所有类都要实现Cloneable接口。而且仔细想想,这好像还是浅拷贝
(4)通过对象序列化实现深拷贝(推荐)
@Data@AllArgsConstructor@NoArgsConstructorpublic class SheepOfDeepCopy implements Serializable {private static final long UID = 1L;private String name;private String color;private Sheep sheep;// 用此种方式其引用类型一定要实现SerializationClone接口,否则报错public SheepOfDeepCopy SerializationClone() {// 因为要序列化,所有先创建流对象ByteArrayOutputStream bos;ObjectOutputStream oos;ByteArrayInputStream bis;ObjectInputStream ois;try {// 序列化bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);// 将当前对象以对象流的方式输出oos.writeObject(this);// 反序列化bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);SheepOfDeepCopy sheepOfDeepCopy = (SheepOfDeepCopy) ois.readObject();return sheepOfDeepCopy;} catch (Exception e) {e.printStackTrace();return null;} finally {// 关闭流操作// TODO try-with-resource}}}
优化:使用try-with-resource替换try-catch-finally
基本介绍:
try-with-resources语句是一种声明了一种或多种资源的try语句。资源是指在程序用完了之后必须要关闭的对象。try-with-resources语句保证了每个声明了的资源在语句结束的时候都会被关闭。任何实现了java.lang.AutoCloseable接口的对象,和实现了java.io.Closeable接口的对象,都可以当做资源使用。
@Data@AllArgsConstructor@NoArgsConstructorpublic class SheepOfDeepCopy implements Serializable {private static final long UID = 1L;private String name;private String color;private Sheep sheep;// 用此种方式其引用类型一定要实现SerializationClone接口,否则报错public SheepOfDeepCopy SerializationClone() {try (// 因为要序列化,所有先创建流对象// 序列化ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);// 反序列化ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);) {SheepOfDeepCopy sheepOfDeepCopy = (SheepOfDeepCopy) ois.readObject();return sheepOfDeepCopy;} catch (Exception e) {e.printStackTrace();return null;}}}
总结


