原始模型模式

通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。

一.克隆满足的条件

1.对任何的对象X,都有:x.clone() != x。换言之,克隆对象与原对象不是同一个对象。

2.对任何的对象x,都有:x.clone().getClass == x.getClass(),换言之,克隆对象与原对象的类型一样。

3.如果对象x的equals()方法定义恰当的话,那么x.clone().equals(x)应当是成立的。

二.原始模型模式的结构

原始模型模式有两种表现形式:第一种是简单形式,第二种是登记形式。这两种形式仅仅是原始模型模式的不同实现,但是由于他们的区别影响了模式结构的细节。

1.简单形式的原始模型模式


原始模型模式

这种形式涉及三个角色:

* 客户(Client):客户类提出创建对象的请求。

* 抽象原型(Prototype):这是一个抽象角色,通常由一个接口或者Java抽象类实现。此角色给出所有的具体原型类所需的接口。

* 具体原型(Concrete Prototype):被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

Client:

<code>public class Client {
private Prototype prototype;
public void operation(Prototype example){
Prototype p = (Prototype)example.clone();
}
}/<code>

Prototype:

<code>public interface Prototype extends Cloneable{
Object clone();
}/<code>

ConcreteProtype:

<code>public class ConcretePrototype implements Prototype {
/**
* 克隆方法
* @return
*/
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e){
return null;
}
}
}/<code>

2.登记形式的原始模型模式


原始模型模式

如下的角色:

* 客户端(client):客户端类向管理员提出创建对象的请求。

* 抽象原型(Prototype):这是一个抽象角色,通常由一个接口或抽象类实现。

* 具体原型(Concrete Prototype):被复制的对象。需要实现抽象的原型角色所要求的接口。

* 原型管理器(Prototype Manager):创建具体原型类的对象,并记录每一个被创建的对象。

Prototype:

<code>public interface Prototype extends Cloneable {
public Object clone();
}/<code>

ConcretePrototype:

<code>public class ConcretePrototype implements Prototype {
/**
* 克隆方法
* @return
*/
@Override
public synchronized Object clone() {
Prototype temp = null;
try {
temp = (Prototype) super.clone();

return temp;
}catch (CloneNotSupportedException e){
System.out.println("Clone failed.");
}finally {
return temp;
}
}
}/<code>

PrototypeManager:

<code>public class PrototypeManager {
private Vector objects = new Vector();

/**
* 聚集管理方法;增加一个新的对象
* @param object
*/
public void add(Prototype object){
objects.add(object);
}

/**
* 聚集管理方法:取出聚集中的一个对象
* @param i
* @return
*/
public Prototype get(int i){
return (Prototype) objects.get(i);
}

/**
* 聚集管理方法:给出聚集的大小
* @return
*/
public int getSize(){
return objects.size();
}
}/<code>

client:

<code>public class CLient {
private PrototypeManager mgr;
private Prototype prototype;
public void registerPrototype(){
prototype = new ConcretePrototype();
Prototype copytype = (Prototype) prototype.clone();
mgr.add(copytype);
}
}/<code>

三.深复制和浅复制

1.浅复制

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的应用都仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

2.深复制

被复制对象的所有的变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原来的那些被引用的对象。

3.利用串行化来做深复制

把对象写到流里的过程是串行化过程,但是在java程序师圈子里又非常形象地称为”冷冻“或者”腌咸菜“过程;而把对象从流中读出来的并行化过程则叫做”解冻“或者”回鲜“过程。应当指出的是,写到流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此”淹成咸菜“的只是对象的一个拷贝,java咸菜还可以回鲜。

在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。

<code>public Object deepClone(){
//将对象写到流里
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.write(this);
//从流里读回来
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return oi.readObject();

}/<code>

这样做的前提就是对象以及对象内部所有应用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象可否设成transient,从而将之排除在复制过程之外。

浅复制显然比深复制更容易实现,因为Java语言的所有类都会继承一个clone()方法,而这个clone()方法所做的正是浅复制。

有一些对象,比如线程(Thread)对象和Socket对象,是不能简单复制或共享的。不管使用深复制还是浅复制,只要涉及这样的间接对象,就必须把间接对象设成transient而不予复制;或者由程序自行创建出相当的同种对象,权且当做复制件使用。


原始模型模式


分享到:


相關文章: