原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。工作原理是将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。
使用原型模式非常简单,实现一个接口,重写一个方法即完成了原型模式。
因为克隆比较常用,所以Java提供了Cloneable接口,所以我们并不需要去编写Prototype接口,只需要实现Cloneable接口即可。不过Cloneable
实现的是浅拷贝,如果想实现深拷贝,我们可以使用Serializable
接口。下面我们会细说分别使用浅拷贝与深拷贝实现原型模式。
在Java中,基本类型有整数类型(long、int、short、byte
),浮点类型(float、double
),字符类型(char
),布尔类型(boolean
)。
除此之外所有的类型都是引用类型。
从存储来说,基本类型与引用类型的区别在于:
在浅拷贝中:
接下来我们使用Resume类来讲解。
具体原型类
package ProtoType.ShallowCopy;import java.util.List;/*** @Author: 少不入川* @Date: 2022/11/28 21:19*/
public class Resume implements Cloneable{private String name;private int age;private List technologyStack;public Resume(){}public Resume(String name, int age, List technologyStack){this.name = name;this.age = age;this.technologyStack = technologyStack;}public List getTechnologyStack() {return technologyStack;}public void setTechnologyStack(List technologyStack) {this.technologyStack = technologyStack;}public String getName() {return name;}public int getAge() {return age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Resume{" +"name='" + name + '\'' +", age=" + age +", technologyStack=" + technologyStack +'}';}// 使用public修饰符方便调用@Overridepublic Object clone(){Resume resume = null;try{resume = (Resume) super.clone();}catch (Exception e){e.printStackTrace();}return resume;}
}
测试类
package ProtoType.ShallowCopy;import java.util.ArrayList;/*** @Author: 少不入川* @Date: 2022/11/28 21:58*/
public class ShallowCopyTest {public static void main(String[] args) {Resume resume1 = new Resume("张三", 20, new ArrayList<>());Resume resume2 = (Resume) resume1.clone();// 引用型变量使用==判等判断的是引用型变量指向地址是否相同System.out.println("两个对象所指向内存地址是否相同:" + (resume1 == resume2));System.out.println("两个对象的成员变量name所指向的内存地址是否相同:" + (resume1.getTechnologyStack() == resume2.getTechnologyStack()));}
}
控制台结果
两个对象所指向内存地址是否相同:false
两个对象的成员变量name所指向的内存地址是否相同:true
在深拷贝中:
具体原型类
package ProtoType.DeepCopy;import java.io.*;
import java.util.List;/*** @Author: 少不入川* @Date: 2022/11/28 21:58*/
public class Resume implements Serializable {private String name;private int age;private List technologyStack;public Resume(){}public Resume(String name, int age, List technologyStack){this.name = name;this.age = age;this.technologyStack = technologyStack;}public List getTechnologyStack() {return technologyStack;}public void setTechnologyStack(List technologyStack) {this.technologyStack = technologyStack;}public String getName() {return name;}public int getAge() {return age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Resume{" +"name='" + name + '\'' +", age=" + age +", technologyStack=" + technologyStack +'}';}public Object deepClone() {//创建流对象ByteArrayOutputStream bos = null;ObjectOutputStream oos = null;ByteArrayInputStream bis = null;ObjectInputStream ois = null;try {//序列化bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);//当前这个对象以对象流的方式输出oos.writeObject(this);//反序列化bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);Resume resume = (Resume) ois.readObject();return resume;} catch (Exception e) {e.printStackTrace();return null;} finally {try {bos.close();oos.close();bis.close();ois.close();} catch (Exception e2) {System.out.println(e2.getMessage());}}}}
测试类
package ProtoType.DeepCopy;import java.util.ArrayList;/*** @Author: 少不入川* @Date: 2022/11/28 22:09*/
public class DeepCopyTest {public static void main(String[] args) {Resume resume1 = new Resume("张三", 20, new ArrayList<>());Resume resume2 = (Resume) resume1.deepClone();// 引用型变量使用==判等判断的是引用型变量指向地址是否相同System.out.println("两个对象所指向内存地址是否相同:" + (resume1 == resume2));System.out.println("两个对象的成员变量name所指向的内存地址是否相同:" + (resume1.getTechnologyStack() == resume2.getTechnologyStack()));}
}
控制台输出
两个对象所指向内存地址是否相同:false
两个对象的成员变量name所指向的内存地址是否相同:false