概述
原型模式用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的
类图
原型模式也是一种很简单的模式,其核心就是使用了对象的克隆
代码实现
public class Classes {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Student implements Cloneable{
private String name;
private int age;
private Classes classes;
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;
}
public Classes getClasses() {
return classes;
}
public void setClasses(Classes classes) {
this.classes = classes;
}
@Override
protected Student clone() {
Student stu = null;
try {
stu = (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
@Override
public String toString() {
return "Student[name=" + name + ",age=" + age + ",class=" + classes.getName() + "]";
}
}
public class Client {
public static void main(String[] args){
Student stu1 = new Student();
stu1.setName("stu1");
stu1.setAge(10);
Classes classes = new Classes();
classes.setName("class1");
stu1.setClasses(classes);
Student stu2 = stu1.clone();
stu2.setName("stu2");
System.out.println(stu1.toString());
System.out.println(stu2.toString());
}
}
优缺点
优点
- 性能优良。原型模式是在内存中进行二进制流拷贝,要比直接new一个对象的性能要好很多
- 逃避构造函数的约束。原型模式直接在内存中克隆对象,不调用构造函数(也是缺点)
缺点
- 必须实现 Cloneable 接口
- 当类的内部结构比较复杂时,实现起来比较复杂
使用场景
- 资源优化场景,当类初始化需要消化非常多的资源时,可以考虑使用原型模式
- 性能和安全要求的场景,过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
- 一个对象有多个使用者进行修改时,可以考虑将对象拷贝多份供不同的调用者使用
注意事项
- 由于原型模式是直接在内存中拷贝对象,对象的构造函数不会被执行
public class People implements Cloneable{
public People(){
System.out.println("构造函数被执行了");
}
private String name;
private ArrayList<String> list;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<String> getList() {
return list;
}
public void setList(ArrayList<String> list) {
this.list = list;
}
@Override
protected People clone(){
People people = null;
try {
people = (People) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return people;
}
@Override
public String toString() {
return "People[name=" + name + ",list=" + list.toString() + "]";
}
}
public class Client {
public static void main(String[] args){
People p1 = new People();
p1.setName("p1");
People p2 = p1.clone();
}
}
输出结果:
构造函数被执行了
---------------------
从输出结果可以看出来,调用clone方法时没有执行构造方法
- 要注意浅拷贝风险
public class Client {
public static void main(String[] args){
People p1 = new People();
List<String> list = new ArrayList<String>();
p1.setName("p1");
list.add("aaa");
p1.setList(list);
People p2 = p1.clone();
p2.setName("p2");
p2.getList().add("bbb");
System.out.println(p1.toString());
System.out.println(p2.toString());
}
}
输出结果:
构造函数被执行了
People[name=p1,list=[aaa, bbb]]
People[name=p2,list=[aaa, bbb]]
从输出结果可以看出来,clone后People内部的list并没有被clone出来,还是指向同一个list,这就是浅拷贝。
如果想实现深拷贝,则需要修改一下clone方法
protected People clone(){
People people = null;
try {
people = (People) super.clone();
people.list = (ArrayList<String>) this.list.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return people;
}
总结一下
- 原型模式用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
- 原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的
- 原型模式的优点:
- 性能优良。原型模式是在内存中进行二进制流拷贝,要比直接new一个对象的性能要好很多
- 逃避构造函数的约束。原型模式直接在内存中克隆对象,不调用构造函数(也是缺点)
- 原型模式的缺点:
- 必须实现 Cloneable 接口
- 当类的内部结构比较复杂时,实现起来比较复杂
- 原型模式的使用场景:
- 资源优化场景,当类初始化需要消化非常多的资源时,可以考虑使用原型模式
- 性能和安全要求的场景,过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
- 一个对象有多个使用者进行修改时,可以考虑将对象拷贝多份供不同的调用者使用
- 注意事项
- 由于原型模式是直接在内存中拷贝对象,对象的构造函数不会被执行
- 要注意浅拷贝风险
欢迎您关注Java天堂公众号,专注于分享Java相关技