原型模式介绍
定义: 原型模式(Prototype Design Pattern)用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
原型模式主要解决的问题
如果创建对象的成本比较大,比如对象中的数据是经过复杂计算才能得到,或者需要从RPC接口或者数据库等比较慢的IO中获取,这种情况我们就可以使用原型模式,从其他已有的对象中进行拷贝,而不是每次都创建新对象,进行一些耗时的操作.
原型模式的优点
性能好,基于内存二进制流拷贝,比直接new 一个对象性能上提升许多。
可以使用深克隆方式保存对象的状态 ,使用原型模式将对象复制一份并将其状态保存起来,简化了创建过程
浅克隆
浅克隆 通过 clone 创建一个与源对象完全相同的对象信息,对于基本值类型按值信息拷贝过去,对于对象类型采用会指向原有对象信息引用原有内存地址
实现了Cloneable接口,以指示Object.clone()方法,该方法对该类的实例进行逐个字段的复制是合法的。
在没有实现Cloneable接口的实例上调用Object的clonze方法将导致抛出CloneNotSupportedException异常。
按照约定,实现这个接口的类应该覆盖Object。使用公共方法克隆(受保护的)。有关重写此方法的详细信息,请参阅Object.clone()。
注意,这个接口不包含clone方法。因此,不可能仅仅因为对象实现了这个接口就克隆它。即使以反射方式调用clone方法,也不能保证它一定会成功。
如果不实现Cloneable接口,会抛出CloneNotSupportedException异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| public class Demo1Prototype implements Cloneable{ private String name; private String age;
private Demo2Prototype prototype;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAge() { return age; }
public void setAge(String age) { this.age = age; }
public Demo2Prototype getPrototype() { return prototype; }
public void setPrototype(Demo2Prototype prototype) { this.prototype = prototype; }
@Override public Demo1Prototype clone() throws CloneNotSupportedException { return (Demo1Prototype) super.clone(); } }
public class Demo2Prototype { private String test;
public String getTest() { return test; }
public void setTest(String test) { this.test = test; } }
public class Main { public static void main(String[] args) throws CloneNotSupportedException { Demo1Prototype demo1Prototype = new Demo1Prototype(); demo1Prototype.setAge("13"); demo1Prototype.setName("张三"); Demo2Prototype demo2Prototype = new Demo2Prototype(); demo2Prototype.setTest("test"); demo1Prototype.setPrototype(demo2Prototype); System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName() + demo1Prototype.getPrototype().getTest()); Demo1Prototype clone = demo1Prototype.clone(); clone.setAge("12"); Demo2Prototype prototype = clone.getPrototype(); prototype.setTest("test2"); System.out.println(clone.toString() + clone.getAge() + clone.getName() + prototype.getTest()); System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName() + demo1Prototype.getPrototype().getTest()); } }
# 输出信息 PrototypeModel.Demo1Prototype@3b07d32913张三test PrototypeModel.Demo1Prototype@4162934612张三test2 PrototypeModel.Demo1Prototype@3b07d32913张三test2
|
深克隆
上面引用对象重复的问题,我们只要对引用对象同样进行clone() 方法的再次调用就可以避免创建重复的对象信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| public class Demo1Prototype implements Cloneable{ private String name; private String age;
private Demo2Prototype prototype;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAge() { return age; }
public void setAge(String age) { this.age = age; }
public Demo2Prototype getPrototype() { return prototype; }
public void setPrototype(Demo2Prototype prototype) { this.prototype = prototype; }
@Override public Demo1Prototype clone() throws CloneNotSupportedException { Demo1Prototype prototype1 = (Demo1Prototype) super.clone(); Demo2Prototype clone = prototype1.getPrototype().clone(); prototype1.setPrototype(clone); return prototype1; } }
public class Demo2Prototype implements Cloneable{ private String test;
public String getTest() { return test; }
public void setTest(String test) { this.test = test; }
@Override public Demo2Prototype clone() throws CloneNotSupportedException{ return (Demo2Prototype) super.clone(); } }
# 输出信息 Demo1Prototype demo1Prototype = new Demo1Prototype(); demo1Prototype.setAge("13"); demo1Prototype.setName("张三"); Demo2Prototype demo2Prototype = new Demo2Prototype(); demo2Prototype.setTest("test"); demo1Prototype.setPrototype(demo2Prototype); System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName() + demo1Prototype.getPrototype().getTest()); Demo1Prototype clone = demo1Prototype.clone(); Demo2Prototype prototype = clone.getPrototype(); prototype.setTest("test2"); System.out.println(clone == demo1Prototype); System.out.println(clone.toString() + clone.getAge() + clone.getName() + prototype.getTest()); System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName() + demo1Prototype.getPrototype().getTest());
|
或者通过序列化的方式去实现
Serializable接口是启用其序列化功能的接口。实现java.io.Serializable 接口的类是可序列化的。没有实现此接口的类将不能使它们的任意状态被序列化或逆序列化。
序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| import java.io.Serializable;
public class Demo1Prototype implements Serializable,Cloneable{ private String name; private String age;
private Demo2Prototype prototype;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAge() { return age; }
public void setAge(String age) { this.age = age; }
public Demo2Prototype getPrototype() { return prototype; }
public void setPrototype(Demo2Prototype prototype) { this.prototype = prototype; }
@Override public Demo1Prototype clone() throws CloneNotSupportedException { Demo1Prototype prototype1 = (Demo1Prototype) super.clone(); return prototype1; } }
import java.io.Serializable;
public class Demo2Prototype implements Serializable { private String test;
public String getTest() { return test; }
public void setTest(String test) { this.test = test; }
}
public class Main { public static void main(String[] args) throws CloneNotSupportedException { Demo1Prototype demo1Prototype = new Demo1Prototype(); demo1Prototype.setAge("13"); demo1Prototype.setName("张三"); Demo2Prototype demo2Prototype = new Demo2Prototype(); demo2Prototype.setTest("test"); demo1Prototype.setPrototype(demo2Prototype); System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName() + demo1Prototype.getPrototype().getTest()); Demo1Prototype clone = null; try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream obs = new ObjectOutputStream(out)){ obs.writeObject(demo1Prototype); ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray()); ObjectInputStream ois = new ObjectInputStream(ios); clone = (Demo1Prototype)ois.readObject(); ois.close(); } catch (Exception ex){
} Demo2Prototype prototype = clone.getPrototype(); prototype.setTest("test2"); System.out.println(clone.toString() + clone.getAge() + clone.getName() + prototype.getTest()); System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName() + demo1Prototype.getPrototype().getTest()); } }
# 执行结果 PrototypeModel.Demo1Prototype@3b07d32913张三test PrototypeModel.Demo1Prototype@759ebb3d13张三test2 PrototypeModel.Demo1Prototype@3b07d32913张三test
|
浅拷贝只能在简单值之间使用, 为避免问题尽量采用深拷贝的方式