设计模式--原型模式
Posted chongcheng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式--原型模式相关的知识,希望对你有一定的参考价值。
如果文章中哪里有问题,希望各位大哥大姐指出,小弟十分感激。
正文
什么是原型模式?
原型模式就是在原有对象的基础上,复制一个新的,但是内容一摸一样的对象。
为什么要使用原型模式?
我们在日常业务中可能会有很多大对象(内部有很多字段),或者创建过程非常繁琐并耗时的对象。对于这些对象,如果我们需要一个新的对象时,重新创建往往是非常繁琐并且耗时的。而使用原型模式,就可以快速创建出一个完全一样的新对象。
怎样使用原型模式?
1:被克隆的类及其引用属性类都要继承Cloneable空接口。
2:被克隆的类及其引用属性类都要实现clone()方法。
3:需要创建新对象时直接调用被克隆的类的clone()方法。
使用原型模式的时候一定要注意浅拷贝和深拷贝:
浅拷贝:Object类的clone()方法会在内存在开辟一块新内容,并将原来对象的信息复制过来。因为基本数据类型内存里面存的就是他的值,所以直接复制过来没有问题;但是引用数据类型保存在内存中的是引用的目标对象的内存地址,所以复制后,新对象和旧对象的引用属性都是同一个内存空间,会相互影响,并不是完全的克隆。这就是浅拷贝。
深拷贝:对于类内部的引用类型的属性,我们也让其实现Cloneable接口,并重写clone方法,然后在外层克隆对象的clone方法中手动执行一下引用类型属性的clone方法,再进行赋值一下,相当于对引用类型的属性进行一次手动赋值。注意,引用类型属性中的引用类型属性,也要这样操作,也就是套娃。
/** * 原型模式 * */ public class clone { public static void main(String[] args) { /** 创建大对象 */ BigObject bigObject = new BigObject(); bigObject.field1 = 111; bigObject.field2 = 111.11; bigObject.field3 = "最外层大对象"; bigObject.field4 = false; bigObject.innerClass1 = new InnerClass1(222,222.22,"第二层innerClass1",true,new InnerClass3(333,333.33,"第三层innerClass1",true)); bigObject.innerClass2 = new InnerClass2(444,444.44,"第二层innerClass2",false); /** 克隆大对象 */ BigObject newObject = bigObject.clone(); /** 输出比较一下 */ System.err.println(bigObject.getClass().getName() + "@" + Integer.toHexString(bigObject.hashCode())); System.err.println(bigObject); System.err.println(""); System.err.println(newObject.getClass().getName() + "@" + Integer.toHexString(newObject.hashCode())); System.err.println(newObject); } } /** * 大对象,需要实现Cloneable这个空接口,这是原型模式的关键 * */ class BigObject implements Cloneable{ int field1; Double field2; String field3; boolean field4; InnerClass1 innerClass1; InnerClass2 innerClass2; public BigObject(int field1, Double field2, String field3, boolean field4, InnerClass1 innerClass1, InnerClass2 innerClass2) { this.field1 = field1; this.field2 = field2; this.field3 = field3; this.field4 = field4; this.innerClass1 = innerClass1; this.innerClass2 = innerClass2; imitateDelay(); } public BigObject() { imitateDelay(); } /** * 模拟延迟 * */ @SuppressWarnings("static-access") private void imitateDelay() { try { // 模拟创建这个对象需要花费2秒 Thread.currentThread().sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 重写克隆方法,这是原型模式的关键 * */ @Override public BigObject clone() { BigObject newObject = null; try { /** * 这里一定要调用父类的构造方法,决不能调用自己子类的构造方法,不然会死循环的 * super.clone()这个方法会在内存中开辟一个新空间,并将当前对象堆中的内容复制过去 * 如果是基本数据类型,则是直接把值复制过去。 * 但如果是引用类型,仅仅只是将引用对象的地址复制过去了而已。这会造成浅拷贝。 * 旧对象和新对象的引用类型属性是同一块内存空间。 * 对于String、Double这种不可变的,我们可以不管他,就算引用同一个内存空间,反正它里面的值是固定不会变的 * */ newObject = (BigObject)super.clone(); newObject.innerClass1 = innerClass1.clone(); newObject.innerClass2 = innerClass2.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return newObject; } @Override public String toString() { return "BigObject [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4 + ", innerClass1=" + innerClass1 + ", innerClass2=" + innerClass2 + "]"; } } class InnerClass1 implements Cloneable{ int field1; Double field2; String field3; boolean field4; InnerClass3 innerClass; @Override public String toString() { return "InnerClass1 [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4 + ", innerClass=" + innerClass + "]"; } public InnerClass1(int field1, Double field2, String field3, boolean field4, InnerClass3 innerClass) { this.field1 = field1; this.field2 = field2; this.field3 = field3; this.field4 = field4; this.innerClass = innerClass; } /** * 重写克隆方法,这是深拷贝的关键 * */ @Override public InnerClass1 clone() { InnerClass1 newObject = null; try { /** * 这里一定要调用父类的构造方法,决不能调用自己子类的构造方法,不然会死循环的 * super.clone()这个方法会在内存中开辟一个新空间,并将当前对象堆中的内容复制过去 * 如果是基本数据类型,则是直接把值复制过去。 * 但如果是引用类型,仅仅只是将引用对象的地址复制过去了而已。这会造成浅拷贝。 * 旧对象和新对象的引用类型属性是同一块内存空间。 * 对于String、Double这种不可变的,我们可以不管他,就算引用同一个内存空间,反正它里面的值是固定不会变的 * */ newObject = (InnerClass1)super.clone(); newObject.innerClass = innerClass.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return newObject; } } class InnerClass2 implements Cloneable{ int field1; Double field2; String field3; boolean field4; @Override public String toString() { return "InnerClass2 [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4 + "]"; } public InnerClass2(int field1, Double field2, String field3, boolean field4) { this.field1 = field1; this.field2 = field2; this.field3 = field3; this.field4 = field4; } /** * 重写克隆方法,这是深拷贝的关键 * */ @Override public InnerClass2 clone() { InnerClass2 newObject = null; try { /** * 这里一定要调用父类的构造方法,决不能调用自己子类的构造方法,不然会死循环的 * super.clone()这个方法会在内存中开辟一个新空间,并将当前对象堆中的内容复制过去 * 如果是基本数据类型,则是直接把值复制过去。 * 但如果是引用类型,仅仅只是将引用对象的地址复制过去了而已。这会造成浅拷贝。 * 旧对象和新对象的引用类型属性是同一块内存空间。 * 对于String、Double这种不可变的,我们可以不管他,就算引用同一个内存空间,反正它里面的值是固定不会变的 * */ newObject = (InnerClass2)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return newObject; } } class InnerClass3 implements Cloneable{ int field1; Double field2; String field3; boolean field4; @Override public String toString() { return "InnerClass3 [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4 + "]"; } public InnerClass3(int field1, Double field2, String field3, boolean field4) { this.field1 = field1; this.field2 = field2; this.field3 = field3; this.field4 = field4; } /** * 重写克隆方法,这是深拷贝的关键 * */ @Override public InnerClass3 clone() { InnerClass3 newObject = null; try { /** * 这里一定要调用父类的构造方法,决不能调用自己子类的构造方法,不然会死循环的 * super.clone()这个方法会在内存中开辟一个新空间,并将当前对象堆中的内容复制过去 * 如果是基本数据类型,则是直接把值复制过去。 * 但如果是引用类型,仅仅只是将引用对象的地址复制过去了而已。这会造成浅拷贝。 * 旧对象和新对象的引用类型属性是同一块内存空间。 * 对于String、Double这种不可变的,我们可以不管他,就算引用同一个内存空间,反正它里面的值是固定不会变的 * */ newObject = (InnerClass3)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return newObject; } }
以上是关于设计模式--原型模式的主要内容,如果未能解决你的问题,请参考以下文章