用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
适用性
当一个系统应该独立于它的产品创建、构成和表示时,要使用P r o t o t y p e模式;以及
• 当要实例化的类是在运行时刻指定时,例如,通过动态装载;或者
• 为了避免创建一个与产品类层次平行的工厂类层次时;或者
• 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们
可能比每次用合适的状态手工实例化该类更方便一些。
它对客户隐藏了
1。具体的产品类,因此减少了客户知道的名字的数目。此外,这些模式使客户无需改变即可使与特定应用相关的类。
2.运行时刻增加和删除产品 P r o t o t y p e允许只通过客户注册原型实例就可以将一个新的具体产品类并入系统。它比其他创建型模式更为灵活,因为客户可以在运行时刻建立和删除原型。
3. 改变值以指定新对象 高度动态的系统允许你通过对象复合定义新的行为—例如,通为一个对象变量指定值—并且不定义新的类。你通过实例化已有类并且将这些实例注册
为客户对象的原型,就可以有效定义新类别的对象。客户可以将职责代理给原型,从而表现新的行为。
4.改变结构以指定新对象 许多应用由部件和子部件来创建对象。例如电路设计编辑器就是由子电路来构造电路的 。为方便起见,这样的应用通常允许你实例化复杂的、用户定
义的结构,比方说,一次又一次的重复使用一个特定的子电路。
5.减少子类的构造
6. 用类动态配置应用 一些运行时刻环境允许你动态将类装载到应用中
P r o t o t y p e的主要缺陷是每一个P r o t o t y p e的子类都必须实现C l o n e操作,这可能很困难。例如,当所考虑的类已经存在时就难以新增 C l o n e操作。当内部包括一些不支持拷贝或有循环引
用的对象时,实现克隆可能也会很困难的。
初始化克隆对象 当一些客户对克隆对象已经相当满意时,另一些客户将会希望使用他们所选择的一些值来初始化该对象的一些或是所有的内部状态。一般来说不可能在 C l o n e操作中传递这些值,因为这些值的数目由于原型的类的不同而会有所不同。一些原型可能需要多个初始化参数,另一些可能什么也不要。在 C l o n e操作中传递参数会破坏克隆接口的统一性。
在java,拷贝一个对象可以调用对象的clone()方法,必须实现Cloneable接口。对象的拷贝分为两种:深拷贝与浅拷贝。所谓深拷贝指的是拷贝出来的对象与原有对象不共享任何数据,这里可以假设一个对象含有一个引用类型的字段A,那么拷贝出来的新对象与原有对象的字段A分别指向不同内存位置,也就是说修改新对象的字段A不会影响原对象的字段A(新对象与原有对象除了类型相同之外没有任何关系)。浅拷贝则不然,如果一个对象中含有一个引用类型的字段A,那么在通过浅拷贝得到新对象之后,新对象与原对象的字段A指向的是同一个内存位置,显然,对新对象字段A的修改必定要影响原对象的字段A,这可以说是原型设计模式最关键的部分。
在Java中Prototype模式变成clone()方法的使用,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。
Jdk原型模式应用
1. ArrayList的clone实现
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
......
public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = (E[])new Object[size];
System.arraycopy(elementData, 0, v.elementData, 0, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
。。。。。。
}
3. HashMap的clone实现
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{
.......
public Object clone() {
HashMap<K,V> result = null;
try {
result = (HashMap<K,V>)super.clone();
} catch (CloneNotSupportedException e) {
// assert false;
}
result.table = new Entry[table.length];
result.entrySet = null;
result.modCount = 0;
result.size = 0;
result.init();
result.putAllForCreate(this);
return result;
}
......
}