设计模式之原型模式prototype

所谓的原型模式,就是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
1.首先需要了解java的clone技术
我理解的很简单,无非是把一个对象进行复制粘贴。那么,来看一下JAVA语言中是如何来实现的这个步骤的。我们依次需要知道以下这些事。

1.Object对象中有一个clone()方法。而且是protected。

2.继承于Object的类一般都可以实现这个方法(有特殊的,比如StringBuffer等,官方定的,不去研究它)。

3.想被clone的对象需要实现接口Cloneable。如果此对象的类不能实现接口Cloneable,则会抛出CloneNotSupportedExcetion。

4.所有的数组都被视为实现接口Cloneable。

5.clone分为浅clone(又称影子clone)和深clone。

6.Object类本身不实现接口Cloneable,所以在类为Object的对象上调用clone方法,将会导致在运行时抛出异常。

关键所在深克隆和浅克隆,那到底他们之间有什么区别呢?
首先看一下例子:


public abstract class CloneClass implements Cloneable {
public int aInt;

public Object clone() {
CloneClass o = null;
try {
o = (CloneClass) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return o;
}
}





public class UnCloneA {
private int i;

public UnCloneA(int ii) {
i = ii;
}

public void doublevalue() {
i *= 2;
}

public String toString() {
return Integer.toString(i);
}
}




public class CloneB implements Cloneable {
public int aInt;
public UnCloneA unCloneA = new UnCloneA(111);

public Object clone() {
CloneB o = null;
try {
o = (CloneB) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return o;
}
}




public class Test {
public static void main(String args[]) {
CloneB b1 = new CloneB();
b1.aInt = 11;
System.out.println("before clone,b1.aInt = " + b1.aInt);
System.out.println("before clone,b1.unCA = " + b1.unCloneA);
CloneB b2 = (CloneB) b1.clone();
b2.aInt = 22;
b2.unCloneA.doublevalue();
System.out.println("=================================");
System.out.println("after clone,b1.aInt = " + b1.aInt);
System.out.println("after clone,b1.unCA = " + b1.unCloneA);
System.out.println("=================================");
System.out.println("after clone,b2.aInt = " + b2.aInt);
System.out.println("after clone,b2.unCA = " + b2.unCloneA);

}
}


输出结果:

before clone,b1.aInt = 11
before clone,b1.unCA = 111
=================================
after clone,b1.aInt = 11
after clone,b1.unCA = 222
=================================
after clone,b2.aInt = 22
after clone,b2.unCA = 222

可见,当执行clone这个动作的时候,系统首先开辟一个和它一样的空间。然后分别对其内容进行复制。复制过程中,如果是基本类型,没什么说的,直接把值复制过来。如果不是基本类型,复制的则是该类型对象的引用。

这样的clone就是所谓的浅clone。那很显然,如果上面复制的过程中,对于非基本类型实现的不是一个引用复制,而是创建一个新的一样的对象(其实也是一个clone步骤),那么就是所谓的深clone。对于深度克隆只不过是clone的一种扩展,还有N深clone等等。对于这些,和我们要研究的原型模式没有多少关系。

1、浅克隆:

a. 提供一个类作为克隆的原型,该类实现了Clonable接口

b. 在该类中覆盖Object类的clone()方法,采用super.clone()方法完成克隆

c. 在外部使用场合先产生一个原型对象,然后调用其clone()方法产生克隆对象

2、深克隆:

a. 提供一个类作为克隆的原型,该类实现了Serializable接口

b. 在该类中覆盖Object类的clone()方法,采用序列化的方法完成克隆(对象流的读写)

c.在外部使用场合先产生一个原型对象,然后调用其clone()方法产生克隆对象


二、Prototype模式与深、浅克隆:

使用Object.clone()方法进行的克隆是“浅克隆”-被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。浅克隆的步骤如下:

①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。

②在派生类中覆盖基类的clone()方法,并声明为public。

③在派生类的clone()方法中,调用super.clone()。

④在派生类中实现Cloneable接口。


为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()要识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。

要实现“深克隆”-被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

深克隆需要使用Java中提供的对象串行化功能-即把要复制的对象写入到一个缓冲流,然后通过输入流读入,完成对象的复制

下面是深克隆与浅克隆的代码

public class SuperStar implements Cloneable, Serializable {
public String name;
public int height;
public Skill mySkill;

public Object clone() {
Object o = null;
try {
o = super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return o;
}

public Object deepClone() throws Exception {
Object o = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); // (ByteArrayOutputStream)此类实现了一个输出流,其中
// 的数据被写入一个字节数组。缓冲区会随着数据的不断写入而自动增长。
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this); // 通过Serialization机制将自身写入该缓冲区

// 找到刚才开辟的缓冲区准备读取
ByteArrayInputStream bis = new ByteArrayInputStream(bos
.toByteArray()); //
ObjectInputStream ois = new ObjectInputStream(bis);
// 将刚才写入的内容读入一个新的对象
o = ois.readObject();

bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return o;
}

}



public class Skill implements Serializable{
public int strength;
public int jumping;
}



public class Test {
public static void main(String args[]) throws Exception{
SuperStar s1=new SuperStar();
s1.name="姚明";
s1.height=226;
s1.mySkill=new Skill();
s1.mySkill.jumping=50;
s1.mySkill.strength=20;

System.out.println(s1.name+" " + s1.height +" "+s1.mySkill.jumping);

SuperStar s2=(SuperStar) s1.clone();

// SuperStar s2=(SuperStar) s1.deepClone();
s2.name="潘长江";
s2.height=100;
s2.mySkill.jumping=10;
s2.mySkill.strength=5;

System.out.println(s2.name+" " + s2.height+" " +s2.mySkill.jumping);
System.out.println(s1.name+" " + s1.height +" "+s1.mySkill.jumping);
}
}


浅克隆 结果
姚明 226 50
潘长江 100 10
姚明 226 10


深克隆 结果

姚明 226 50
潘长江 100 10
姚明 226 50

JAVA中的clone方法,其实现是native的。这也就意味着它的执行效率是远高于new一个新对象的。所以,当需要生成大量相似对象的时候,可以考虑下应用clone,也就是原形模式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值