原型模式是简单程度仅次于单例模式的简单模式,它的定义可以简单理解为对象的拷贝,通过拷贝的方式创建一个已有对象的新对象,这就是原型模式。
原型模式的优缺点
优点很明显就是可以绕过繁琐的构造函数,快速创建对象,且比直接new一个对象性能优良,因为是直接内存二进制流拷贝。原型模式非常适合于你想要向客户隐藏实例创建的创建过程的场景,提供客户创建未知类型对象的选择。
原型模式最主要的缺点是每一个类都必须配备一个克隆方法。配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类来说不是很难,而对于已经有的类不一定很容易,特别是当一个类引用不支持序列化的间接对象,或者引用含有循环结构的时候。
原型模式的代码简直不要太简单,简单到不能再简单了,只需要实现Cloneable接口,然后覆写clone方法,调用super.clone就可以实现简单的对象复制了。
值得注意的是,使用clone方法创建的新对象的构造函数是不会被执行的,也就是说会绕过任何构造函数(有参和无参),因为clone方法的原理是从堆内存中以二进制流的方式进行拷贝,直接分配一块新内存。
方法一:
protected person clone() {
// 直接调用父类Object实现clone克隆,但是必须实现Cloneable接口才能克隆对象
person clone =(person) super.clone();
return clone }
下面的代码是通过序列化和反序列化的方式实现对象的拷贝的,通过实现Serializable接口,对象可以写到一个流里(序列化),再从流里读回来(反序列化),便可以重建对象。可以看到输出结果中新对象保留了原始对象的基本类型数据(name和age),同时针对新对象操作List数据不会影响原始对象,这说明跟原始对象是完全隔离开了,是两个完全独立的对象。
能够使用这种方式做的前提是,对象以及对象内部所有引用到的对象都是可序列化的,否则,就需要仔细考察那些不可序列化的对象可否设成transient,从而将之排除在复制过程之外。
有一些对象,比如线程(Thread)对象或Socket对象,是不能简单复制或共享的。不管是使用浅度克隆还是深度克隆,只要涉及这样的间接对象,就必须把间接对象设成transient而不予复制;或者由程序自行创建出相当的同种对象。
方法二:
protected person clone() {
//将对象写到流里 必须实现Serializable接口才能进行反序列化对象
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//从流里读回来
ByteArrayInputStream bis = newByteArrayInputStream( bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (DeepCopyExample) ois.readObject(); }