目录
1.原型设计模式介绍
- 原型模式:是用于创建重复的对象,同时又能保证性能,属于创建型模式。
- 这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。
- 类型:浅拷贝和深拷贝
- 核心组成
- 1.Prototype: 声明克隆方法的接口,是所有具体原型类的公共父类,Cloneable接口
- 2.ConcretePrototype:具体原型类
- 3.Client: 让一个原型对象克隆自身从而创建一个新的对象
- 应用场景
- 1.一个对象多个修改者的场景。
- 2.通过 new 产生一个对象需要非常繁琐的数据准备或访问权限
- 3.如果系统要保存对象的状态,做备份使用
2.浅拷贝
要想实现对象拷贝,就必须实现Cloneable接口,并且实现clone()克隆方法。
java
public class Student implements Cloneable{
private String age;
private String name;
private List<String> hobby=new ArrayList<>();
public Student() {
System.out.println("构造器被调用~");
}
public List<String> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 实现克隆方法-浅拷贝
*
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
/**
* toString方法,方便查询
*
* @return
*/
@Override
public String toString() {
return "Student{" +
"age='" + age + '\'' +
", name='" + name + '\'' +
", hobby=" + hobby +
'}';
}
}
创建学生1并设置相关属性,通过s1克隆s2,只修改姓名和爱好
java
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Student s1 = new Student();
s1.setAge("18");
s1.setName("小张");
s1.getHobby().add("ccc");
Student s2 = s1.clone();
s2.setName("小小张");
s2.getHobby().add("bbb");
System.out.println("浅拷贝:"+s1.toString());
System.out.println("浅拷贝:"+s2.toString());
}
}
发现年龄不变和爱好,姓名改变
通过debug发现,s1和s2属性hobby的地址一样
上面拷贝模式属于浅拷贝 :
- 如果原型对象的成员变量是基本数据类型(int, double, byte, boolean, char等) ,将复制一份给克隆对象;
- 如果原型对象的成员变量是引用数据类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向****相同的内存地址
- 通过覆盖object类的clone()方法可以实现浅克隆
3.深拷贝
无论原型对象的成员变量是基本数据类型还是引用类型,都将复制一份给克隆对象,如果需要实现深克隆,可以通过**序列化(Serializable)**等方式来实现
要想实现深拷贝 需要实现Serializable接口,实现序列化和反序列化
java
public class Student implements Serializable {
private String age;
private String name;
private List<String> hobby=new ArrayList<>();
public Student() {
System.out.println("构造器被调用~");
}
public List<String> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 实现克隆方法-深拷贝
* @return
*/
public Student deepClone() {
try {
//输出 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
//输出 序列化
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Student copyStudent = (Student) ois.readObject();
return copyStudent;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* toString方法,方便查询
*
* @return
*/
@Override
public String toString() {
return "Student{" +
"age='" + age + '\'' +
", name='" + name + '\'' +
", hobby=" + hobby +
'}';
}
}
修改姓名和爱好
java
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Student s1 = new Student();
s1.setAge("18");
s1.setName("小张");
s1.getHobby().add("aaa");
Student s2 = s1.deepClone();
s2.setName("小小张");
s2.getHobby().add("bbb");
System.out.println("深拷贝:"+s1.toString());
System.out.println("深拷贝:"+s2.toString());
}
}
发现hobby的地址不同,并且hobby的值也不同
优点:
- 性能提高:当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,可以提高新实例的创建效率
- 可辅助实现撤销操作,使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用恢复到历史状态
缺点:
- 需要为每一个类配备一个克隆方法,对已有的类进行改造时,需要修改源代码,违背了"开闭原则
- 必须实现 Cloneable 接口或Serializable接口