一.原型(ProtoType)模式定义:
给出一个原型对象实例来指定创建对象的类型,并通过拷贝这些原型的方式来创建新的对象。
原型模式的简单程度仅次于单例模式的简单模式,它的定义可以理解为对象的拷贝,通过拷贝一个已有对象创建新对象,这就是原型模式。
设计类图:
二.场景
需要大量创造重复场景且构造函数复杂时,比如需要先读取数据或者加载文件
三.原型模式又称为克隆模式:有两种
浅克隆:实现cloneable接口
深度克隆:方式一.实现cloneable接口;方式二.序列化和反序列化
四.浅克隆与深度克隆----通过cloneable实现
java实现克隆必须实现cloneable接口,该接口是个空接口
浅克隆:类本身实现cloneable接口,引用类或者内部类未实现cloneable接口
1 package com.design.clone; 2 3 public class TestClone implements Cloneable { 4 private String testCloneName="hello"; 5 private int testCloneInt = 1; 6 private TestObj testObj = new TestObj(); 7 @Override 8 protected TestClone clone() throws CloneNotSupportedException { 9 return (TestClone) super.clone(); 10 } 11 12 public String getTestCloneName() { 13 return testCloneName; 14 } 15 16 public void setTestCloneName(String testCloneName) { 17 this.testCloneName = testCloneName; 18 } 19 20 public int getTestCloneInt() { 21 return testCloneInt; 22 } 23 24 public void setTestCloneInt(int testCloneInt) { 25 this.testCloneInt = testCloneInt; 26 } 27 28 public TestObj getTestObj() { 29 return testObj; 30 } 31 32 public void setTestObj(TestObj testObj) { 33 this.testObj = testObj; 34 } 35 36 @Override 37 public String toString() { 38 final StringBuilder sb = new StringBuilder("TestClone{"); 39 sb.append("testCloneHashCode='").append(this.hashCode()).append('\''); 40 sb.append(",testCloneName='").append(testCloneName).append('\''); 41 sb.append(", testCloneInt=").append(testCloneInt); 42 sb.append(", testObjHashCode=").append(testObj.hashCode()); 43 sb.append(", testObjInt=").append(testObj.getTestObjInt()); 44 sb.append('}'); 45 return sb.toString(); 46 } 47 } 48 49 50 //引用代码未实现clone接口 51 package com.design.clone; 52 53 public class TestObj { 54 private int testObjInt=1; 55 56 public int getTestObjInt() { 57 return testObjInt; 58 } 59 60 public void setTestObjInt(int testObjInt) { 61 this.testObjInt = testObjInt; 62 } 63 } 64 65 测试: 66 public static void main(String[] args) throws CloneNotSupportedException { 67 TestClone testClone = new TestClone(); 68 System.out.println("克隆前:" + testClone.toString()); 69 TestClone cloneObj = testClone.clone(); 70 System.out.println("克隆的新对象:" + cloneObj.toString()); 71 System.out.println("================修改克隆对象的值,看是否会修改原对象属性值=============="); 72 cloneObj.setTestCloneName("world"); 73 cloneObj.setTestCloneInt(-2); 74 cloneObj.getTestObj().setTestObjInt(0); 75 System.out.println("被克隆对象testCone=" + testClone.toString()); 76 System.out.println("克隆对象:" + cloneObj.toString()); 77 }
结果:
从打印结果可以看出来原对象testClone 的hashCode和克隆出来的对象的hashcode不一样,也就是说clone并不是把原对象地址引用复制给新对象,而是重新再内存中开辟了一块新空间,将testClone复制过去,将新地址给新对象
但是testObj的hashCode却是相同的,也就是两个指向了同一个对象,当其中一个对象改变引用的属性时,另外一个也会跟着改变,上面打印的改变的克隆的testObj的属性,原对象的也跟着改变了,
testClone对象的基本数据类型属性在clone的时候开辟了新内存,所以互不影响
深度克隆:引用对象也实现cloneable接口, 同时TestClone的clone方法需要对TestObj进行克隆赋值操作
1 package com.design.clone; 2 3 public class TestObj implements Cloneable{ 4 private int testObjInt=1; 5 6 public int getTestObjInt() { 7 return testObjInt; 8 } 9 10 public void setTestObjInt(int testObjInt) { 11 this.testObjInt = testObjInt; 12 } 13 14 @Override 15 protected TestObj clone() throws CloneNotSupportedException { 16 return (TestObj) super.clone(); 17 } 18 } 19 20 package com.design.clone; 21 22 public class TestClone implements Cloneable { 23 private String testCloneName="hello"; 24 private int testCloneInt = 1; 25 private TestObj testObj = new TestObj(); 26 @Override 27 protected TestClone clone() throws CloneNotSupportedException { 28 TestClone clone = (TestClone) super.clone(); 29 clone.setTestObj(clone.getTestObj().clone()); 30 return clone; 31 } 32 33 public String getTestCloneName() { 34 return testCloneName; 35 } 36 37 public void setTestCloneName(String testCloneName) { 38 this.testCloneName = testCloneName; 39 } 40 41 public int getTestCloneInt() { 42 return testCloneInt; 43 } 44 45 public void setTestCloneInt(int testCloneInt) { 46 this.testCloneInt = testCloneInt; 47 } 48 49 public TestObj getTestObj() { 50 return testObj; 51 } 52 53 public void setTestObj(TestObj testObj) { 54 this.testObj = testObj; 55 } 56 57 @Override 58 public String toString() { 59 final StringBuilder sb = new StringBuilder("TestClone{"); 60 sb.append("testCloneHashCode='").append(this.hashCode()).append('\''); 61 sb.append(",testCloneName='").append(testCloneName).append('\''); 62 sb.append(", testCloneInt=").append(testCloneInt); 63 sb.append(", testObjHashCode=").append(testObj.hashCode()); 64 sb.append(", testObjInt=").append(testObj.getTestObjInt()); 65 sb.append('}'); 66 return sb.toString(); 67 } 68 } 69 70 package com.design.clone; 71 72 public class Client { 73 public static void main(String[] args) throws CloneNotSupportedException { 74 TestClone testClone = new TestClone(); 75 System.out.println("克隆前:" + testClone.toString()); 76 TestClone cloneObj = testClone.clone(); 77 System.out.println("克隆的新对象:" + cloneObj.toString()); 78 System.out.println("================修改克隆对象的值,看是否会修改原对象属性值=============="); 79 cloneObj.setTestCloneName("world"); 80 cloneObj.setTestCloneInt(-2); 81 cloneObj.getTestObj().setTestObjInt(0); 82 System.out.println("被克隆对象testCone=" + testClone.toString()); 83 System.out.println("克隆对象:" + cloneObj.toString()); 84 } 85 }
测试结果:
从上面打印结果看出来:1.可懂对象和被克隆对象的hashCode不同,属性值也不同,引用对象的hashCode也不一样, 属性值也不一样,说明两者互不影响
TestClone以及引用对象完全不复制了一份,所以而知是互不影响的
四.序列化与反序列化实现深度克隆
1 package com.design.clone.serialize; 2 3 import java.io.Serializable; 4 5 public class TestClone implements Serializable { 6 private String testCloneName = "hello"; 7 private int testCloneInt = 0; 8 private TestObj testObj = new TestObj(); 9 10 public String getTestCloneName() { 11 return testCloneName; 12 } 13 14 public void setTestCloneName(String testCloneName) { 15 this.testCloneName = testCloneName; 16 } 17 18 public int getTestCloneInt() { 19 return testCloneInt; 20 } 21 22 public void setTestCloneInt(int testCloneInt) { 23 this.testCloneInt = testCloneInt; 24 } 25 26 public TestObj getTestObj() { 27 return testObj; 28 } 29 30 public void setTestObj(TestObj testObj) { 31 this.testObj = testObj; 32 } 33 34 @Override 35 public String toString() { 36 final StringBuilder sb = new StringBuilder("TestClone{"); 37 sb.append("testCloneHashCode='").append(this.hashCode()).append('\''); 38 sb.append(",testCloneName='").append(testCloneName).append('\''); 39 sb.append(", testCloneInt=").append(testCloneInt); 40 sb.append(", testObjHashCode=").append(testObj.hashCode()); 41 sb.append(", testObjInt=").append(testObj.getTestObjInt()); 42 sb.append('}'); 43 return sb.toString(); 44 } 45 } 46 47 48 package com.design.clone.serialize; 49 50 import java.io.Serializable; 51 52 public class TestObj implements Serializable { 53 private int testObjInt = 1; 54 55 public int getTestObjInt() { 56 return testObjInt; 57 } 58 59 public void setTestObjInt(int testObjInt) { 60 this.testObjInt = testObjInt; 61 } 62 } 63 64 package com.design.clone.serialize; 65 66 import java.io.*; 67 68 public class BeanUtils { 69 70 public static Object clone(Object t) throws IOException, ClassNotFoundException { 71 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 72 ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); 73 objectOutputStream.writeObject(t); 74 objectOutputStream.flush(); 75 ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); 76 ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 77 return objectInputStream.readObject(); 78 } 79 } 80 81 package com.design.clone.serialize; 82 83 import java.io.IOException; 84 85 public class SerializeTest { 86 public static void main(String[] args) throws IOException, ClassNotFoundException { 87 TestClone testClone = new TestClone(); 88 TestClone clone = (TestClone) BeanUtils.clone(testClone); 89 clone.setTestCloneInt(5); 90 clone.setTestCloneName("world"); 91 clone.getTestObj().setTestObjInt(10); 92 System.out.println("被克隆对象testCone=" + testClone.toString()); 93 System.out.println("克隆对象:" + clone.toString()); 94 } 95 }
测试结果:结果也是互不影响