1.原型模式
原型模式术语对象的创建模式。通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对像的方法创建出更多同类型的对象。
2.Java中的clone
Java语言提供的Cloneable接口支起一个作用,就是在运行时期通知Java虚拟机可以安全地在这个类上使用clone()方法。通过这个方法可以得到一个对象的复制。
clone()方法需要满足以下的描述:
(1)对任何的对象x,都有:x.clone() != x。克隆对象与源对象不是同一个对象。
(2)对任何的对象x,都有:x.clone().getClass == x.getClass(),类型一样。
(3)如果对象x的equals()方法定义恰当的话,那么x.clone().equals(x) 应当是成立的.
上面3个条件,前两个是必须的,3是可选的。
Java的API中,凡是提供的clone()的类,都满足了上面这些条件。所以实现clone()方法,推荐都遵守这3个条件.
3.简单形式的原型模式
类图:
角色:
客户(client)角色:客户类提出创建对象的请求
抽象原型(Prototype):原型的抽象接口
具体原型(ConcretePrototype):被复制的角色
源码:
client类
public class Client
{
public void operation(Prototype example)
{
Prototype p = (Prototype) example.clone();
}
private Prototype prototype;
}
Prototype
public interface Prototype extends Cloneable
{
Object clone();
}
ConcretePrototype
public class ConcretePrototype implements Prototype
{
public Object clone()
{
try
{
return super.clone();
}
catch(CloneNotSupportedException e)
{
//write your code here
return null;
}
}
}
4.登记形式的原型模式
类图:
角色:
原型管理器(Prototype Manager):创建具体原型类对象,并记录被创建的对象。
客户端(client):向管理员提出创建请求。
其它与简单形式一样。
源码示例:
Prototype manager
public class PrototypeManager
{
/**
* 添加对象
*/
public void add(Prototype object)
{
objects.add(object);
}
/**
* 获得对象
*/
public Prototype get(int i)
{
return (Prototype) objects.get(i);
}
public int getSize()
{
return objects.size();
}
/*
* 记录被创建的对象
*/
private Vector objects = new Vector();
}
client
public class Client
{
private PrototypeManager mgr;
private Prototype prototype;
public void registerPrototype()
{
prototype = new ConcretePrototype();
Prototype copy = (Prototype)prototype.clone();
mgr.add(copy);
}
}
5.两种形式的比较
如果需要创建的原型对象数目比较少而且比较固定的话,可以使用简单形式,原型对象由客户端自己保存。
如果创建的对象数目不固定,可以采用登记形式,对象由manager保存和管理。
6.深克隆和浅克隆
前面示例代码使用的都是浅克隆,实现Cloneable接口。
(1)浅克隆:被复制的对象所有变量都含有与原来的对象相同的值,而所有的对对象的引用都仍然指向原来的对象。
(2)深克隆:被复制的对象的所有变量都含有与原来对象相同的值,而所有的对对象的引用指向被复制的新对象。在Java中深克隆一般使用序列化实现。
public Object deepClone()
throws IOException, OptionalDataException, ClassNotFoundException
{
//将对象写到流里
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
//从流里写回来
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return (oi.readObject());
}
代码中被克隆的对象能被复制的前提是 对象时串行化的。
7.使用场景
系统中产品类是动态加载的,而且产品类具有一定得等级结构。
在运行过程中不知道对象的具体类型,可使用原型模式创建一个相同类型的对象,或者在运行过程中动态的获取到一个对象的状态。
8.优点和缺点
优点:
(1)允许动态地增加或者减少产品类
(2)简化的创建结构
(3)可以在运行时动态的获取对象的类型以及状态,从而创建一个对象
(4)原型模式适用于任何等级结构,不需要非得有任何事先确定的等级结构。
缺点:
每一个产品都需要配备一个克隆方法。对已有的类不合适。