ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 原型设计模式 ### 是一种对象创建型模式,使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,主要用于创建重复的对象,同时又能保证性能。 #### 工作原理是将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。 ### 应该是最简单的设计模式了,实现一个接口,重写一个方法即完成了原型模式。 ### ## 应用场景 ### 创建新对象成本较大,新的对象可以通过原型模式对已经有的对象进行复制来获得。 如果系统要保存对象的状态,做备份使用。 ### ## 原型设计模式涉及到了深拷贝和浅拷贝 ### ### 浅拷贝 ### 如果原型对象的成员变量是基本数据类型(int、double、byte、boolean、char等),将复制⼀份给克隆对象; 如果原型对象的成员变量是引⽤类型,则将引⽤对象的地址复制⼀份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址; 通过覆盖Object类的clone()⽅法可以实现浅克隆。 ### ### 深拷⻉ ### ⽆论原型对象的成员变量是基本数据类型还是引⽤类型,都将复制⼀份给克隆对象,如果需要实现深克隆,可以通过序列化(Serializable)等⽅式来实现。 ### **原型模式是内存⼆进制流的拷⻉,⽐new对象性能⾼很多,使⽤的时候记得注意是选择浅拷⻉还是深拷⻉** ### ## 原型设计模式的优点 ### 当创建新的对象实例较为复杂时,使⽤原型模式可以简化对象的创建过程,可以提⾼新实例的创建效率 ### 可辅助实现撤销操作,使⽤深克隆的⽅式保存对象的状态,使⽤原型模式将对象复制⼀份并将其状态保存起来,以便在需要的时候使⽤恢复到历史状态 ### ## 具体实现(云效代码study-java项目当中设计模式当中有代码案例): ### ~~~ package com.goldnecis.设计模式.原型模式; import java.io.*; import java.util.ArrayList; import java.util.List; public class Persion implements Cloneable, Serializable { private String name; private int age; private List<String> list = new ArrayList<>(); public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } public Persion() { System.out.println("构造函数调用"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override protected Persion clone() throws CloneNotSupportedException { return (Persion) super.clone(); } /** * 对象深拷贝 * @return */ public Object deepClone() { //首先,创建一个ByteArrayOutputStream对象baos,它是一个字节数组输出流,用于将对象序列化为字节数组。 //然后,创建一个ObjectOutputStream对象oos,它是一个对象输出流,用于将对象写入baos中进行序列化操作。 //通过调用oos.writeObject(this),将当前对象this写入baos,实现对象的序列化。 //接下来,创建一个ByteArrayInputStream对象bais,它是一个字节数组输入流,用于从字节数组中读取对象数据。 //然后,创建一个ObjectInputStream对象ois,它是一个对象输入流,用于从bais中读取对象并进行反序列化操作。 //通过调用ois.readObject(),从bais中读取反序列化的对象数据,并将其转换为Persion类型的对象copyObj。 //最后,返回copyObj作为方法的结果,表示深拷贝后得到的新对象。 //如果在序列化或反序列化过程中出现异常,将打印异常堆栈信息,并返回null。 try { //输出 序列化 ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); //输入 反序列化 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); Persion copyObj = (Persion) ois.readObject(); return copyObj; } catch (Exception e) { e.printStackTrace(); return null; } } } ~~~ 再来看如何调用进行深浅拷贝 ### ~~~ package com.goldnecis.设计模式.原型模式; //原型模式的实现 //其实就是类的深拷贝和浅拷贝 public class Main { public static void main(String[] args) throws CloneNotSupportedException { Persion person1 = new Persion(); person1.setAge(10); person1.setName("小滴课堂-老王"); //首先被拷贝对象的list当中已经有了aaa 如果是浅拷贝 person1当中aaa如果persion2设置了ccc那么person1当中的list也会有ccc结果就是aaa,ccc persion2当中也是aaa,ccc //如果是深拷贝,person1当中的list就是aaa 因为是深拷贝 所以persion2当中再去设置ccc和persion1就没有任何的关系 所以persion2当中的list就是aaa,ccc persion1当中就是aaa person1.getList().add("aaa"); //浅拷贝 //如果是浅拷贝并且如果原型对象的成员变量是基本数据类型(int double byte boolean char 等)将复制一份给克隆对象 //如果原型对象的成员变量是引用数据类型,则将引用对象的内存地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址 //通过覆盖Object类的clone()方法可以实现浅拷贝 Persion persion2 = person1.clone(); //深拷贝 //无论原型对象的成员变量是基本数据类型还是引用数据类型,都将复制一份给克隆对象,如果需要实现深克隆,可以通过序列化Serializable等方式来实现 //原型模式是内存二进制流的拷贝,比new对象性能高很多,使用的时候记得注意是选择浅拷贝还是深拷贝 //Persion persion2 = (Persion) person1.deepClone(); persion2.setName("Anna小姐姐"); persion2.getList().add("ccc"); System.out.println("person1="+person1.getName()+", age="+person1.getAge()); System.out.println("person2="+persion2.getName()+", age="+persion2.getAge()); //首先被拷贝对象的list当中已经有了aaa 如果是浅拷贝 person1当中aaa如果persion2设置了ccc那么person1当中的list也会有ccc结果就是aaa,ccc persion2当中也是aaa,ccc //如果是深拷贝,person1当中的list就是aaa 因为是深拷贝 所以persion2当中再去设置ccc和persion1就没有任何的关系 所以persion2当中的list就是aaa,ccc persion1当中就是aaa System.out.println(person1.getList().toString()); System.out.println(persion2.getList().toString()); } } ~~~ ### ![](https://img.kancloud.cn/cf/ea/cfea675a7b73dd83eac03572143a1e72_1876x953.png) ### ![](https://img.kancloud.cn/f9/eb/f9ebbeef18e12b80c8f06cc5badd244e_1609x870.png)