原型(prototype)模式:用一个已经创建好的实例作为原型,通过复制该原型对象来创建一个和原型相同或者相似的对象
优点:
- java自带的原型模式基于内存二进制流的复制,在性能上要比new对象要快的多
- 可以使用深拷贝的方式保存对象的状态,使用原型模式复制对象并将之保存起来,简化了创建对象的过程
缺点:
- 需要为每一个类都配备一个clone方法
- clone方法位于代码的内部,当对已有的类进行修改的时候,需要修改代码,违背了开闭原则
- 当深拷贝的是嵌套对象的时候,代码实现相对复杂
适用场景
- 对象之间相同或相似,即只是个别的几个属性不同的时候。
- 创建对象成本较大,例如初始化时间长,占用CPU太多,或者占用网络资源太多等,需要优化资源。
- 创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性。
- 系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。
原型模式的结构:
- 抽象原型类:规定了具体原型对象必须实现的接口
- 具体原型类:实现了抽象原型类的clone方法,他是可复制的对象
- 访问类:使用具体原型类中的clone方法来复制新的对象
分类:
- 浅拷贝:新对象中的属性和原对象完全相同,非基本类型的属性指向原属性所在内存地址。java中Object类中的clone方法就已经实现了浅拷贝
- 深拷贝:新对象中的属性和非基本属性都会被拷贝,不再指向原内存地址
浅拷贝
看结果发现,浅拷贝没有拷贝引用类型的属性
public class Prototype {
public static void main(String[] args) throws CloneNotSupportedException {
// 定义学生1,和老师1
Student s1 = new Student();
Teacher t1 = new Teacher();
t1.setName("张三的老师");
s1.setTeacher(t1);
s1.setName("张三");
// 拷贝学生1
Student s2 = s1.clone();
s2.setName("李四");
s2.getTeacher().setName("李四的老师");
System.out.println("学生"+s1.name+"的老师是:"+s1.getTeacher().getName()); // 学生张三的老师是:李四的老师
System.out.println("学生"+s2.name+"的老师是:"+s2.getTeacher().getName()); // 学生李四的老师是:李四的老师
}
static class Student implements Cloneable{
// 学生姓名
String name;
Teacher teacher;
// 省略get set
/**
* 重写clone 对学生类进行拷贝
*/
@Override
protected Student clone() throws CloneNotSupportedException {
return (Student)super.clone();
}
}
static class Teacher implements Cloneable{
// 老师姓名
String name;
// 省略get set
@Override
protected Teacher clone() throws CloneNotSupportedException {
return (Teacher) super.clone();
}
}
}
深拷贝
对上述代码进行改造,只需要重写学生类中的拷贝方法,实现深拷贝
/**
* 重写clone 对学生类进行拷贝
*/
@Override
protected Student clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
Teacher t1 = this.teacher.clone();
student.setTeacher(t1);
return student;
}