原型模式:
顾名思义。将一个对象当作原型,通过对象克隆的方式复制,创建出更多与原型对象相同类型的对象。
类型:
创建型模式
原型对象关系图:
原型对象的3个角色:
- 客户(Client)角色:客户类提出创建对象的请求。
- 抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。
- 具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
首先是一个简单的示例:
创建一个用于测试深浅克隆问题的类:
/**
* Create by zhaihongwei on 2018/3/14
*/
public class Test {
}
创建Prototype接口对象
/**
* Create by zhaihongwei on 2018/3/14
*
* 提供一个供所有需要进行克隆操作的接口
*/
public interface Prototype {
Object clone();
}
创建具体需要克隆的对象ConcretePrototype
/**
* Create by zhaihongwei on 2018/3/14
*/
public class ConcretePrototype implements Prototype {
// test1 和 test2 和 test仅用来测试
private int test1;
private String test2;
private Test test;
public Test getTest() {
return test;
}
public void setTest(Test test) {
this.test = test;
}
public int getTest1() {
return test1;
}
public void setTest1(int test1) {
this.test1 = test1;
}
public String getTest2() {
return test2;
}
public void setTest2(String test2) {
this.test2 = test2;
}
@Override
public ConcretePrototype clone() {
ConcretePrototype concretePrototype = new ConcretePrototype();
concretePrototype.setTest1(this.test1);
concretePrototype.setTest(this.test);
concretePrototype.setTest2(this.test2);
return concretePrototype;
}
}
创建Client对象
/**
* Create by zhaihongwei on 2018/3/14
*/
public class Client {
private Prototype prototype;
public Client(Prototype prototype){
this.prototype = prototype;
}
public Prototype startClone(Prototype concretePrototype) {
return (Prototype) concretePrototype.clone();
}
}
测试:
/**
* Create by zhaihongwei on 2018/3/14
*/
public class PrototypeTest {
public static void main(String[] args) {
// 创建一个具体的需要克隆的对象
ConcretePrototype concretePrototype = new ConcretePrototype();
// 填充属性,方便测试
concretePrototype.setTest1(1);
concretePrototype.setTest2("prototype");
Test test = new Test();
concretePrototype.setTest(test);
System.out.println(concretePrototype);
// 创建Client对象,准备开始克隆
Client client = new Client(concretePrototype);
ConcretePrototype concretePrototypeClone = (ConcretePrototype) client.startClone(concretePrototype);
System.out.println(concretePrototypeClone);
System.out.println("克隆对象中的引用类型地址值:" + concretePrototypeClone.getTest());
System.out.println("原对象中的引用类型地址值:" + concretePrototype.getTest());
System.out.println("没有深克隆:"+(concretePrototypeClone.getTest() == concretePrototype.getTest()));
}
}
测试结果:
simple.ConcretePrototype@606d8acf
simple.ConcretePrototype@470e2030
克隆对象中的引用类型地址值:simple.Test@3fb4f649
原对象中的引用类型地址值:simple.Test@3fb4f649
没有深克隆:true
改造:
Java中已经提供了一个方便我们进行clone操作的接口Cloneable,我们已经不需要自己手动提供Prototype接口类了
浅克隆案例:
创建一个用于测试深浅克隆问题的类:
/**
* Create by zhaihongwei on 2018/3/14
*/
public class Test {
}
创建具体需要克隆的对象ConcretePrototype
/**
* Create by zhaihongwei on 2018/3/14
*/
public class ConcretePrototype implements Cloneable {
// test1 和 test2 仅用来测试
private int test1;
private String test2;
private Test test;
public Test getTest() {
return test;
}
public void setTest(Test test) {
this.test = test;
}
public int getTest1() {
return test1;
}
public void setTest1(int test1) {
this.test1 = test1;
}
public String getTest2() {
return test2;
}
public void setTest2(String test2) {
this.test2 = test2;
}
public Object clone() throws CloneNotSupportedException {
ConcretePrototype concretePrototype = (ConcretePrototype) super.clone();
return concretePrototype;
}
}
创建Client类
/**
* Create by zhaihongwei on 2018/3/14
*/
public class Client {
private ConcretePrototype concretePrototype;
public Client(ConcretePrototype concretePrototype){
this.concretePrototype = concretePrototype;
}
public ConcretePrototype startClone(ConcretePrototype concretePrototype) throws CloneNotSupportedException {
return (ConcretePrototype) concretePrototype.clone();
}
}
测试类:
/**
* Create by zhaihongwei on 2018/3/14
*/
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
// 创建一个具体的需要克隆的对象
ConcretePrototype concretePrototype = new ConcretePrototype();
// 填充属性,方便测试
concretePrototype.setTest1(1);
concretePrototype.setTest2("prototype");
Test test = new Test();
concretePrototype.setTest(test);
System.out.println(concretePrototype);
// 创建Client对象,准备开始克隆
Client client = new Client(concretePrototype);
ConcretePrototype concretePrototypeClone = (ConcretePrototype) client.startClone(concretePrototype);
System.out.println(concretePrototypeClone);
System.out.println("克隆对象中的引用类型地址值:" + concretePrototypeClone.getTest());
System.out.println("原对象中的引用类型地址值:" + concretePrototype.getTest());
System.out.println("没有深克隆:"+(concretePrototypeClone.getTest() == concretePrototype.getTest()));
}
}
测试结果:
shallow.ConcretePrototype@69222c14
shallow.ConcretePrototype@782830e
克隆对象中的引用类型地址值:shallow.Test@470e2030
原对象中的引用类型地址值:shallow.Test@470e2030
没有深克隆:true
结论:
从结果可以看出对象已经进行了复制,同时也看出了原型模式存在的一个问题,引用类型的对象没有进行复制,而是将引用的地址赋值了,即深克隆和浅克隆问题。
浅克隆:
只负责克隆按值传递的数据(基本数据类型),而不复制它所引用的对象,换言之,所有的对其他对象的引用都仍然指向原来的对象。
深克隆:
除了浅度克隆要克隆的值外,还负责克隆引用类型的数据。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深度克隆把要复制的对象所引用的对象都复制了一遍,而这种对被引用到的对象的复制叫做间接复制。
深克隆案例:
创建一个用于测试深浅克隆问题的类:(需要实现Serializable接口)
/**
* Create by zhaihongwei on 2018/3/14
*/
public class Test implements Serializable{
}
创建具体需要克隆的对象ConcretePrototype(需要实现Serializable接口)
/**
* Create by zhaihongwei on 2018/3/14
*/
public class ConcretePrototype implements Cloneable,Serializable {
// test1 和 test2 仅用来测试
private int test1;
private String test2;
private Test test;
public Test getTest() {
return test;
}
public void setTest(Test test) {
this.test = test;
}
public int getTest1() {
return test1;
}
public void setTest1(int test1) {
this.test1 = test1;
}
public String getTest2() {
return test2;
}
public void setTest2(String test2) {
this.test2 = test2;
}
// 深克隆
public Object deepClone() throws IOException, ClassNotFoundException{
//将对象写到流里
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//从流里读回来
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
创建Client类
/**
* Create by zhaihongwei on 2018/3/14
*/
public class Client {
private ConcretePrototype concretePrototype;
public Client(ConcretePrototype concretePrototype){
this.concretePrototype = concretePrototype;
}
public ConcretePrototype startClone(ConcretePrototype concretePrototype) throws CloneNotSupportedException, IOException, ClassNotFoundException {
return (ConcretePrototype) concretePrototype.deepClone();
}
}
测试类:
/**
* Create by zhaihongwei on 2018/3/14
*/
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
// 创建一个具体的需要克隆的对象
ConcretePrototype concretePrototype = new ConcretePrototype();
// 填充属性,方便测试
concretePrototype.setTest1(1);
concretePrototype.setTest2("prototype");
Test test = new Test();
concretePrototype.setTest(test);
System.out.println(concretePrototype);
// 创建Client对象,准备开始克隆
Client client = new Client(concretePrototype);
ConcretePrototype concretePrototypeClone = (ConcretePrototype) client.startClone(concretePrototype);
System.out.println(concretePrototypeClone);
System.out.println("克隆对象中的引用类型地址值:" + concretePrototypeClone.getTest());
System.out.println("原对象中的引用类型地址值:" + concretePrototype.getTest());
System.out.println("没有深克隆:"+(concretePrototypeClone.getTest() == concretePrototype.getTest()));
}
}
测试结果:
deep.ConcretePrototype@69222c14
deep.ConcretePrototype@27f674d
克隆对象中的引用类型地址值:deep.Test@1d251891
原对象中的引用类型地址值:deep.Test@16b4a017
没有深克隆:false
从结果可以看出Test对象已经不是原来的地址值了,说明Test对象也进行了重新创建。
深克隆的原理:
- 利用序列化实现深度克隆,把对象写到流里的过程是序列化(Serialization)过程;而把对象从流中读出来的过程则叫反序列化(Deserialization)过程。应当指出的是,写到流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。
- 在Java语言里深度克隆一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的拷贝)写到一个流里(序列化),再从流里读回来(反序列化),便可以重建对象。
个人总结:
至此已经学完了5中创建型模式,下面将继续学习,结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。加油!!!