这篇推文学习创建型模式最后一种-原型模式,该模式的思想是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象,以便使用
浅拷贝:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。深拷贝:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深拷贝进行了完全彻底的复制,而浅拷贝不彻底。 Animal:具体原型类。实现克隆的具体操作。 Manager(这边用测试类代替):管理者类。让一个原型克隆自身,从而获得一个新的对象。所有的Java类都继承至Object,而Object类提供了一个clone()方法,该方法可以将一个java对象复制一份,因此在java中可以直接使用clone()方法来复制一个对象。但是需要实现clone的Java类必须要实现一个接口:Cloneable.该接口表示该类能够复制且具体复制的能力,如果不实现该接口而直接调用clone()方法会抛出CloneNotSupportedException异常
Java中任何实现了Cloneable接口的类都可以通过调用clone()方法来复制一份自身然后传给调用者。一般而言,clone()方法满足:
对任何的对象x,都有x.clone() !=x,即克隆对象与原对象不是同一个对象。 对任何的对象x,都有x.clone().getClass()==x.getClass(),即克隆对象与原对象的类型一样。 如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
public class Animal implements Cloneable{
private String name;
private Integer age;
@Override
protected Object clone(){
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
public Animal(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//此处省略getter setter
}
测试:
public class CloneTest {
public static void main(String[] args) {
//创建
Animal cat = new Animal("cat", 2);
//克隆
Animal cat_2 = (Animal) cat.clone();
//cat
System.out.println("cat:" + cat);
//cat_2
System.out.println("cat_2:" + cat_2);
//同个对象?false
System.out.println( cat == cat_2);
//x.clone().getClass()==x.getClass(),即克隆对象与原对象的类型一样
System.out.println( cat.getClass() == cat_2.getClass());/true
}
}
如果创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,能够提高效率。可以使用深克隆保持对象的状态。原型模式提供了简化的创建结构。
在实现深克隆的时候可能需要比较复杂的代码。需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了“开闭原则”。
如果创建新对象成本较大,我们可以利用已有的对象进行复制来获得。如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占内存不大的时候,也可以使用原型模式配合备忘录模式来应用。相反,如果对象的状态变化很大,或者对象占用的内存很大,那么采用状态模式会比原型模式更好。 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。