一、什么是原型模式
原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。
原型模式是一种对象创建型模式,它的工作原理非常简单:将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程。原型模式在软件开发中有较高的使用频率,很多软件提供的复制(Ctrl+C)和粘贴(Ctrl+V)就是原型模式的典型应用。
二、原型模式结构
1.Prototype(抽象原型类):声明克隆方法的接口,是所有具体原型类的公共父类,它可以是抽象类也可以是接口,甚至还可以是具体实现类。
2.ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
3.Client(客户类):在客户类中,让一个原型对象通过克隆自身得到一个新的对象。
三、原型模式实现
1.通用方法实现
通用的克隆实现方法是在具体原型类的克隆方法中实例化一个与自身类型相同的对象并将其返回,同时将相关的参数传入新创建的对象中,保证它们的成员变量相同。
public abstract class Prototype{
public abstract Prototype clone();
}
public class ConcretePrototype extends Prototype{
private String attr; //成员变量
public void setAttr(String attr){
this.attr=attr;
}
public String getAttr(){
return attr;
}
//克隆方法
public Prototype clone(){
Prototype prototype=new ConcretePrototype(); //创建新对象
prototype.setAttr(this.attr);
return prototype;
}
}
在客户类中只需要创建一个ConcretePrototype对象作为原型对象,然后调用其clone()方法即可得到对应的克隆对象。实例代码如下:
...
ConcretePrototype prototype=new ConcretePrototype();
prototype.setAttr("Sunny");
ConcretePrototype copy=(ConcretePrototype)prototype.clone();
...
此方法是原型模式的通用实现,它与编程语言本身的特性无关。
2.Java语言中的clone()方法和Cloneable接口
在Java语言中,所有的Java类均继承自java.lang.Object类,Object类提供了一个clone()方法,可以将一个Java对象复制一份。在Java中可以直接使用Object提供的Clone()方法来实现对象的浅克隆。需要注意的是能够实现克隆的Java类必须实现一个标识接口Cloneable,表示这个Java类支持被复制。如果没有实现Cloneable接口但调用clone()方法,会抛出异常。
public class ConcretePrototype implements Cloneable{
...
public Prototype clone(){
Object object=null;
try{
object=super.clone(); //浅克隆
}
catch(CloneNotSupportedException exception){
System.err.println("Not support cloneable");
}
return (Prototype)object;
}
...
}
在客户端创建原型对象和克隆对象。
Prototype prototype=new ConcretePrototype();
Prototype copy=prototype.clone();
四、浅克隆与深克隆
1.浅克隆
在浅克隆中,如果原型对象的成员变量是值类型(如int、double、byte、boolean等),将复制一份给克隆对象;如果原型对象的成员变量是引用类型(如类、接口、数组等复杂数据结构),则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。简单来说,在浅克隆中,当原型对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有被复制。在Java中clone()方法就是浅克隆。
2.深克隆
在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象。深克隆将原型对象的所有引用对象也复制一份给克隆对象。在Java语言中通过序列化等方式来实现深克隆。序列化就是将对象写入到流中的过程,写到流中的对象是原对象的复制,而原对象仍然存在于内存中。通过序列化实现的复制不仅可以复制对象本身,还可以复制其引用的成员对象,因此通过序列化将对象写入到一个流中,再从流中将其读出来,可以实现深克隆。