今天给大家说一下设计模式中的原型模式
何为原型模式,即以系统中有的一个对象,通过复制它的二进制字节流,直接来获取到该对象,好处是在于不需要进行对象的初始化动作,因为对象的初始化还伴随着一些函数的调用,比如构造函数等,在获取效率上会提高很多
可以用在以下情况
创建该类对象需要耗费资源过大,创建过程较为复杂
这个对象系统中大量使用,且每个调用者都需要对该对象进行个性化操作,比如赋值等
尽然原型模式就是复制对象,那么我们可以使用JDK中提供的API,我们可以把需要复制的类实现Java中的Cloneable接口,然后重写object.clone()方法即可,代码如下
public class Prototype implements Cloneable{
private String desc;
private List<String> foods;
@Override
protected Prototype clone() {
Prototype prototype = null;//声明一个原对象
try {
prototype=(Prototype)super.clone();//复制
} catch (Exception e) {
e.printStackTrace();
}
return prototype;
}
//省略了get、set和toString方法
}
测试代码
public class Test {
public static void main(String[] args) {
//创建源对象
Prototype origin=new Prototype();
origin.setDesc("食谱");
List<String> foods=new ArrayList<String>();
foods.add("火锅");
foods.add("烧烤");
origin.setFoods(foods);
System.out.println("原有对象"+origin);
//通过复制来创建对象
Prototype copy=origin.clone();
System.out.println("复制对象"+copy);
//那么原对象跟复制对象有没有关系呢?
//我们修改下复制对象内部的值
copy.setDesc("美食清单");
copy.getFoods().add("宫爆鸡丁");
//再次输出
System.out.println("原有对象"+origin);
System.out.println("复制对象"+copy);
}
}
结果如下
我们会惊讶的发现,普通变量String desc值在经过复制对象修改后,与原对象确实没有关系了,但是List<> foods却都发生了变化,因为List是要分配内存空间的,说明我们的原对象和复制对象操作了同一块内存,即当存在引用数据类型时,这样的复制只是把对象的引用复制了一份,并没有真正的复制一块内存空间给复制对象,这样的复制叫做浅复制,也叫浅拷贝。
可是我们实现复制的本意就是让原对象和复制对象完完全全没有关系,那么我们只需要在clone方法内部直接分配一块内存就好了,这样的叫做深复制,也叫深拷贝
而在Java中要实现深拷贝,我们可以用序列化的方式。我们在原有Prototype类中新添加一个方法,同时需要实现Serializable接口,其余类内容与之前不变,代码如下
public class Prototype implements Cloneable,Serializable
//实现Serializable接口后再添加以下方法
public Prototype deepClone() {
try {
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
return (Prototype)ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
再运行测试代码
public class Test {
public static void main(String[] args) {
//创建源对象
Prototype origin=new Prototype();
origin.setDesc("食谱");
List<String> foods=new ArrayList<String>();
foods.add("火锅");
foods.add("烧烤");
origin.setFoods(foods);
System.out.println("原有对象"+origin);
//通过复制来创建对象
//注意,这里调用的方法变了
Prototype copy=origin.deepClone();
System.out.println("复制对象"+copy);
//那么原对象跟复制对象有没有关系呢?我们修改下复制对象内部的值
copy.setDesc("美食清单");
copy.getFoods().add("宫爆鸡丁");
//再次输出
System.out.println("原有对象"+origin);
System.out.println("复制对象"+copy);
}
}
查看结果
可以看到我们成功的进行了深拷贝,即复制出来了两个完全不同的对象。
原型模式比较简单,主要是得理解原型模式的意义,以及在复制过程中的深拷贝和浅拷贝的问题,像我们在Spring中创建Bean的时候就有单例模式和原型模式,当我们知道了这两种模式的区别之后,就能在以后的学习和应用中得心应手。
希望今天的文章能给大家带来一定的收获。