设计模式笔记——原型模式

今天看了下原型模式,复习和记录一下。
原型模式,其思想是指,当我们需要创建一个对象的时候,我们可以通过复制(不调用构造函数)一个已有的对象,来获取新的对象,这样获取的对象和原型对象拥有一样的结构、性质,我们可以对他进行重新设置,从而得到一个完全全新的对象。这样的设计模式的出现,主要是为了解决某些对象的初始化需要消耗大量的资源的情况,或者需要操作一个和原型对象一模一样的对象,但是却不能改变原型对象的值,我们也可以直接的得到原型的克隆对象,然后进行操作。说了这么多,相信大家肯定也明白了,原型模式的关键,其实就在一个克隆,使用克隆已有对象的方法,来减少创建对象的开销。
java中原型模式的实现很简单,将你需要拷贝的类实现cloneable接口,然后重写clone函数就可以了。需要获取对象的克隆时,直接调用clone方法就可以,这里需要注意的是,这里的clone方法我们是重写的Object类的clone方法,这个方法被定义为protected类型的,所以重写时,我们需要将他改成public。调用clone函数生成的克隆对象,不调用构造函数,是直接开辟一个和原型一模一样的内存空间,然后将空间中各属性全部按照==来赋值,也就是说,如果类中属性的类型是引用类型,那么得到的克隆对象,持有的属性其实是元对象的属性的一个引用,这点需要特别注意,讲到这个就不得不说一下浅拷贝和深拷贝的问题了,在后面,我们再祥讲。调用clone生成对象,比调用构造函数生成对象在效率上有极大的优势,特别是大的对象。
首先我们创建一个可以进行拷贝操作的类,这个类必须实现cloneable接口,这个接口的作用是,告诉jvm这个类是可以调用Object的clone方法的,和 Serializable接口相似,并没有需要实现的方法。
static class book implements Cloneable{
private auth a;
private int count;
private String name;
public auth getA() {
return a;
}
public void setA(auth a) {
this.a = a;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public book clone() {
book b=null;
try {
b=(book)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return b;
}
}
为了说明clone方法是浅拷贝这个问题,我们故意在成员变量中加入了一个auth类对象:
static class auth{
private String name;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
之后我们在main函数中调用使用这个原型模式:
public static void main(String[] args) {
book b=new book();
auth a=new auth();
a.setId(1);
a.setName(“tom”);
b.setA(a);
b.setCount(2);
b.setName(“jj”);
book b2=b.clone();
System.out.println(b.getCount()==b2.getCount());
System.out.println(b.getName()==b2.getName());
System.out.println(b.getA()==b2.getA());
}
打印的结果:
true
true
true
这充分说明了clone是浅拷贝。

*关于浅拷贝和深拷贝的问题:

以上问题,若要完全实现深拷贝,我们需要利用序列化和反序列化来实现,此时我们的book必须要实现 Serializable接口,同时,如果book类中有非基础数据类型的成员变量,这个成员变量的类也必须实现Serializable接口,在我们这个例子中,就是auth也必须实现serializable接口。

static class book implements Cloneable,Serializable{
private auth a;
private int count;
private String name;
public auth getA() {
return a;
}
public void setA(auth a) {
this.a = a;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public book clone() {
book b=null;
try {
b=(book)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return b;
}
public book deepClone()
{
try {
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream ios=new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(ios);
book b=(book) ois.readObject();
return b;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
static class auth implements Serializable{
private String name;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
与之前的例子相比,只是auth和book类多实现了一个serializable接口,同时我们将深拷贝的内容写到了deepClone这个函数里面,当时,我们也可以直接重写到Object的Clone函数中,事实上,真正使用过程中,我们 就是应该写在clone函数里面。
下面我们来看一下效果:
public static void main(String[] args) {

    book b=new book();
    auth a=new auth();
    a.setId(1);
    a.setName("tom");
    b.setA(a);
    b.setCount(2);
    b.setName("jj");

    book b1=b.deepClone();
    book b2=b.clone();
    System.out.println(b.getCount()==b1.getCount());
    System.out.println(b.getName()==b1.getName());
    System.out.println(b.getA()==b1.getA());
}

结果:
true
false
false
我们可以看见,这个时候,克隆对象中的引用属性,也完全是全新的一个对象了,实现了和原型的全完独立,这样的拷贝,就是比较好的了。

文章例子参考Corn大神的文章,原文链接:
http://www.cnblogs.com/lwbqqyumidi/p/3746821.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值