定义:原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
在应用程序中,有些对象比较复杂,其创建过程过于复杂,而且我们又需要频繁的利用该对象,如果这个时候我们按照常规思维new该对象,那么务必会造成资源浪费,这个时候我们就希望可以利用一个已有的对象来不断对他进行复制就好了,这就是编程中的“克隆”。原型模式直接操作底层二进制流,在创建复杂对象是效率提升明显。
UML类图:
浅克隆与深克隆:
浅克隆:当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
深克隆:除了对象本身被复制外,对象所包含的所有成员变量也将被复制。
浅克隆:
public class Person implements Cloneable {
private String name;
private boolean gender;
private Interest interest;
public Person(String name, boolean gender, Interest interest) {
this.name = name;
this.gender = gender;
this.interest = interest;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public Interest getInterest() {
return interest;
}
public void setInterest(Interest interest) {
this.interest = interest;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender=" + gender +
", interest=" + interest +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
Interest interest = new Interest("摄影");
Person gg = new Person("gg",false,interest);
System.out.println(gg);
Person dxy = (Person)gg.clone();
dxy.setName("dxy");
dxy.setGender(true);
dxy.interest.setName("咖啡");
System.out.println(dxy);
System.out.println(gg);
}
}
class Interest{
private String name;
public Interest(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Interest{" +
"name='" + name + '\'' +
'}';
}
}
运行结果:
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
Person{name='dxy', gender=true, interest=Interest{name='咖啡'}}
Person{name='gg', gender=false, interest=Interest{name='咖啡'}}
浅克隆对于引用类型,只克隆了引用,因此两个对象的interest公共同一个内存地址,一个对象变化,会引起另一个对象响应的变化。
深克隆:
public class Person implements Cloneable {
private String name;
private boolean gender;
private Interest interest;
public Person(String name, boolean gender, Interest interest) {
this.name = name;
this.gender = gender;
this.interest = interest;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public Interest getInterest() {
return interest;
}
public void setInterest(Interest interest) {
this.interest = interest;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender=" + gender +
", interest=" + interest +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone(); //直接调用object对象的clone()方法!
//添加如下代码实现深复制(deep Clone)
Person person = (Person) obj;
person.interest = (Interest)this.interest.clone(); //把属性也进行克隆!
return obj;
}
public static void main(String[] args) throws CloneNotSupportedException {
Interest interest = new Interest("摄影");
Person gg = new Person("gg",false,interest);
System.out.println(gg);
Person dxy = (Person)gg.clone();
dxy.setName("dxy");
dxy.setGender(true);
dxy.interest.setName("咖啡");
System.out.println(dxy);
System.out.println(gg);
}
}
class Interest implements Cloneable {
private String name;
public Interest(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Interest{" +
"name='" + name + '\'' +
'}';
}
}
运行结果:
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
Person{name='dxy', gender=true, interest=Interest{name='咖啡'}}
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
通过对引用类型值Interest添加clone方法,并且对Person对象的clone方法改造,实现深克隆。
此外还可以通过序列化和反序列化的方式实现深复制。
public class Person implements Serializable {
private String name;
private boolean gender;
private Interest interest;
public Person(String name, boolean gender, Interest interest) {
this.name = name;
this.gender = gender;
this.interest = interest;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public Interest getInterest() {
return interest;
}
public void setInterest(Interest interest) {
this.interest = interest;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender=" + gender +
", interest=" + interest +
'}';
}
public static void main(String[] args) throws CloneNotSupportedException,ClassNotFoundException,IOException {
Interest interest = new Interest("摄影");
Person gg = new Person("gg",false,interest);
System.out.println(gg);
//使用序列化和反序列化实现深复制
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(gg);
byte[] bytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
Person dxy = (Person) ois.readObject(); //克隆好的对象!
dxy.interest.setName("咖啡");
System.out.println(dxy);
System.out.println(gg);
}
}
class Interest implements Serializable{
private String name;
public Interest(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Interest{" +
"name='" + name + '\'' +
'}';
}
}
运行结果:
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
Person{name='gg', gender=false, interest=Interest{name='咖啡'}}
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
优点:
当创建对象的实例较为复杂的时候,使用原型模式可以简化对象的创建过程。
直接操作二进制流,可以提高实例的创建效率。
缺点:
需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了开闭原则。
在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重签到引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。
此外clone对象时,不调用构造方法,无视构造方法的权限。