1 定义
原型模式:将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程
2相关概念
值类型:int double byte boolean char等简单数据类型
引用类型:类,接口,数组等复杂类型
浅克隆
如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址.简单来说简单来说:在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制
深克隆
无论原型对象的成员变量是值类型还是引用类型,否将复制一份给克隆对象,克隆对象将原型对象的所有引用对象也复制一份给克隆对象.在深克隆中,除了对象本身被复制外,对象所含的所有成员变量也将复制.
在Java中要实现深克隆,可以通过序列化(Serialization)等方式实现.需要注意的是原型对象和引用类型的成员变量都要实现Serialization接口
3 代码实现
简单的原型模式
public class ConcretePrototype implements Cloneable,Serializable{
private String attr1;
private String attr2;
private String[] arr = new String[]{"aaa","bbb"};
public String getAttr1() {
return attr1;
}
public void setAttr1(String attr1) {
this.attr1 = attr1;
}
public String getAttr2() {
return attr2;
}
public void setAttr2(String attr2) {
this.attr2 = attr2;
}
public String[] getArr() {
return arr;
}
public void setArr(String[] arr) {
this.arr = arr;
}
@Override
public ConcretePrototype clone(){
Object object = null;
try{
object = super.clone();
return (ConcretePrototype) object;
}catch (CloneNotSupportedException e){
System.out.println("不持支复制");
return null;
}
}
public ConcretePrototype deepClone() throws IOException, ClassNotFoundException {
//将对象写入流中
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象从流中取出
ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
return (ConcretePrototype)ois.readObject();
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
ConcretePrototype concretePrototype = new ConcretePrototype();
concretePrototype.setAttr1("attr1");
concretePrototype.setAttr2("attr2");
ConcretePrototype clone = concretePrototype.clone();
System.out.println(clone.getAttr1());
System.out.println(clone.equals(concretePrototype));//false
System.out.println(clone == concretePrototype); //false
System.out.println(clone.getArr()==concretePrototype.getArr());//true
ConcretePrototype deepClone = concretePrototype.deepClone();
System.out.println(deepClone.equals(concretePrototype));//false
System.out.println(deepClone == concretePrototype); //false
System.out.println(deepClone.getArr()==concretePrototype.getArr());//false
}
}
引入原型管理器
public interface Prototype {
Prototype clone();
void common();
}
public class ConcretePrototype1 implements Prototype {
private String attr;
public String getAttr() {
return attr;
}
public void setAttr(String attr) {
this.attr = attr;
}
@Override
public Prototype clone(){
ConcretePrototype1 prototype = new ConcretePrototype1();
prototype.setAttr(this.attr);
return prototype;
}
@Override
public void common() {
System.out.println("this is ConcretePrototype1");
}
}
public class ConcretePrototype2 implements Cloneable,Prototype {
@Override
public Prototype clone() {
Object object = null;
try {
object = super.clone();
} catch (CloneNotSupportedException exception) {
System.err.println("Not support cloneable");
}
return (Prototype )object;
}
@Override
public void common() {
System.out.println("this is ConcretePrototype2");
}
}
public class PrototypeManager {
//定义一个HashTable,用于存储原型对象
private Hashtable<String,Prototype> ht=new Hashtable<String,Prototype>();
private static PrototypeManager pm = new PrototypeManager();
private PrototypeManager(){
ht.put("cp1", new ConcretePrototype1());
ht.put("cp2", new ConcretePrototype2());
}
//增加新的原型对象
public void addPrototype(String key,Prototype prototype){
ht.put(key, prototype);
}
//通过浅克隆获取新的公文对象
public Prototype getProtoType(String key){
return (Prototype)ht.get(key).clone();
}
public static PrototypeManager getPrototypeManager(){
return pm;
}
public static void main(String[] args) {
PrototypeManager pm = PrototypeManager.getPrototypeManager();
Prototype prototype1,prototype2,prototype3;
prototype1 = pm.getProtoType("cp1");
prototype2 = pm.getProtoType("cp2");
prototype1.common();
prototype2.common();
prototype3 = pm.getProtoType("cp1");
System.out.println(prototype1==prototype3);
}
}
4优缺点及适用场景
主要优点:
1)当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率。
2)扩展性较好,由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程,而将具体原型类写在配置文件中,增加或减少产品类对原有系统都没有任何影响。
3)原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式就不需要这样,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品。
4)可以使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(如恢复到某一历史状态),可辅助实现撤销操作。
主要缺点:
1)需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进
行改造时,需要修改源代码,违背了“开闭原则”。
2)在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了
实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。
适用场景:
1)创建新对象成本较大(如初始化需要占用较长的时间,占用太多的CPU资源或网络资源),新的对象可以通过原型模式对已有对象进行复制来获得,如果是相似对象,则可以对其成员变量稍作修改。
2)如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占用内存较少时,可以使用原型模式配合备忘录模式来实现。
3)需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。