概念:
原型模式:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
实现方式:
抽象原型类:规定了具体原型对象必须实现的clone()方法
具体原型类:实现抽象原型类的clone()方法,它是可被复制的对象
访问类:使用具体原型类的clone()方法来复制新的对象
原型模式分为浅克隆、深克隆
实现1:(浅克隆)
java中object类中提供了clone()方法来实现浅克隆, Cloneable接口就是抽象原型类,实现了Cloneable接口的子类就是具体的原型类。如下:
public class Phone implements Cloneable {
private String name;
public Phone() {
System.out.println("调用构造方法创建对象");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Phone clone() throws CloneNotSupportedException {
System.out.println("调用克隆方法创建对象");
return (Phone) super.clone();
}
}
public class Test {
public static void main(String[] args) {
try {
Phone phone1 = new Phone();
phone1.setName("小米手机");
Phone phone2 = phone1.clone();
System.out.println("phone1: "+phone1.getName()+"\nphone2: "+phone2.getName());
phone2.setName("华为手机");
System.out.println("phone1: "+phone1.getName()+"\nphone2: "+phone2.getName());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
输出结果:
从输入结果可以看出,当调用原型类clone方法时,并没有再次调用构造方法。对象的属性也会一同被复制。
实现2:(深克隆)
还是以生产手机为例,这次我们在手机里添加一个CPU类引用。
public class Phone implements Cloneable, Serializable {
private String name;
private Cpu cpu;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cpu getCpu() {
return cpu;
}
public void setCpu(Cpu cpu) {
this.cpu = cpu;
}
@Override
protected Phone clone() throws CloneNotSupportedException {
return (Phone) super.clone();
}
@Override
public String toString() {
return name + " : cpu name:" + cpu.getName() + " version:" + cpu.getVersion();
}
}
public class Cpu implements Serializable {
private String name;
private String version;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
public class Test {
public static void main(String[] args) {
//一 浅克隆 引用对象指向原来的地址,修改属性值,都会一起修改
try {
Phone phone = new Phone();
phone.setName("小米手机");
Cpu cpu = new Cpu();
cpu.setName("骁龙");
cpu.setVersion("850");
phone.setCpu(cpu);
Phone phone2 = phone.clone();
phone2.getCpu().setVersion("888");
System.out.println(phone.toString());
System.out.println(phone2.toString());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("===============");
//二 深克隆 通过序列化对象方式
try {
Phone phone = new Phone();
phone.setName("华为手机");
Cpu cpu = new Cpu();
cpu.setName("麒麟");
cpu.setVersion("900");
phone.setCpu(cpu);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("***/b.txt"));
oos.writeObject(phone);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("***/b.txt"));
Phone phone2 = (Phone) ois.readObject();
ois.close();
phone2.getCpu().setVersion("990");
System.out.println(phone.toString());
System.out.println(phone2.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
由该示例可以得出:
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。(注意String虽然是引用类型,但和其他引用类型的区别在于,原先的string的值一旦创建后,就不会改变使用+/-操作,原先的字符串还是在内存中,+/-完的字符串会写入新分配的内存中,而不会改变原有的堆上的数据。)
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。