原型模式是指调用clone方法或者其他手段来创建对象,事实上,原型模式比较简单,就是一种克隆对象的方法,现在实例化对象并不耗费性能,原型模式也并不常见,但在以下几种情况下,还是需要用到原型模式来克隆已经实例化的对象:
在原型模式中,主要涉及两个类:
Prototype(抽象原型类):声明了clone()方法的接口或者基类,在简单的场景中,并不需要这种基类,只需要直接具体原型类就足够了。
ConcretePrototype(具体原型类):用于实现或者扩展clone()方法的类。
原型模式在Java中实现很简单,只需要原型类实现Cloneable接口并重写clone()即可。
Java中的复制分为浅复制和深复制。
浅复制:Java的浅复制比较简单,只需要实现Cloneable接口并重写clone()就可以了,浅复制只会复制对象的基本数据类型并创建,而引用数据类型还是指向原来的对象。
深复制:深复制无论是是基本数据类型还是引用数据类型都会被重新复制和创建。
总而言之,深复制彻底复制了对象的数据(包括基本数据类型和引用数据类型),而浅复制的复制并不彻底(如果对象有引用数据类型,则忽略了引用数据类型的复制和创建),在实践中,也应该根据实际情况来选择使用深复制还是浅复制,通常,深复制对应于组合关系,浅复制对应聚合关系。
Java原型模式浅复制例子:
1、定义一个抽象原型类ComputerPrototype(其实例子比较简单,也可以不需要抽象原型类,把abstract去掉直接当成具体原型类来使用)
package com.bran.prototype.type1;
public abstract class ComputerPrototype implements Cloneable{
private String cpu;
private String memory;
public ComputerPrototype(){};
public ComputerPrototype(String cpu, String memory) {
this.cpu = cpu;
this.memory = memory;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
//重写clone方法进行复制对象
@Override
protected ComputerPrototype clone() throws CloneNotSupportedException {
return (ComputerPrototype)super.clone();
}
@Override
public String toString() {
return "ComputerPrototype{" +
"cpu='" + cpu + '\'' +
", memory='" + memory + '\'' +
'}';
}
}
2、具体原型类Computer
package com.bran.prototype.type1;
public class Computer extends ComputerPrototype{
public Computer(String cpu, String memory) {
super(cpu, memory);
}
}
3、测试Java原型模式的浅复制
package com.bran.prototype.type1;
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
ComputerPrototype computer1 = new Computer("i7-7500U","16G");
ComputerPrototype computer2 = computer1.clone();
System.out.println(computer1 == computer2);
System.out.println(computer1.toString());
System.out.println(computer2.toString());
}
}
Java原型模式深复制例子:
1、定义具体原型类Computer,例子比较简单,就不使用抽象原型类,深复制要能对引用数据类型也进行复制,所以要定义一个引用对象类Cpu,也实现了Cloneable接口,重写了clone()方法。实现深复制其实也很简单,只需要对浅复制super.clone()的结果再进行一步对引用对象的复制就可以了
package com.bran.prototype.type2;
public class Computer implements Cloneable{
private Cpu cpu;
private String memory;
public Computer() {
}
public Computer(Cpu cpu, String memory) {
this.cpu = cpu;
this.memory = memory;
}
public Cpu getCpu() {
return cpu;
}
public void setCpu(Cpu cpu) {
this.cpu = cpu;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
@Override
protected Computer clone() throws CloneNotSupportedException {
Computer computer = (Computer)super.clone();
//对引用数据类型的复制,再赋值给引用对象的属性
computer.cpu = this.cpu.clone();
return computer;
}
}
2、定义引用对象类Cpu
package com.bran.prototype.type2;
public class Cpu implements Cloneable{
private String type;
public Cpu() {
}
public Cpu(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
protected Cpu clone() throws CloneNotSupportedException {
return (Cpu)super.clone();
}
}
3、测试Java原型模式的深复制
package com.bran.prototype.type2;
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Computer computer = new Computer();
Cpu cpu = new Cpu("i7-7500");
computer.setCpu(cpu);
computer.setMemory("8G");
Computer computer1 = computer.clone();
//比较复制后对象和复制前对象的地址是否一致
System.out.println(computer == computer1);
System.out.println(computer.getCpu() == computer1.getCpu());
}
}