博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
原型模式
阅读量:6469 次
发布时间:2019-06-23

本文共 4319 字,大约阅读时间需要 14 分钟。

原型模式

标签 : Java与设计模式


原型模式

用原型实例指定创建对象的种类, 并通过拷贝这些原型创建新的对象.

原型模式就是通过一个对象再创建另一个可定制的对象, 而且不需要知道任何创建的细节.

因此, 原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建。标准的原型模式的URL类图为:
但由于Java类库已经帮我们实现了一个java.lang.Cloneable接口, 因此我们的实现就简单了些,下面我们模仿多利羊的诞生过程:

/** * 该羊支持克隆 * (浅复制) * Created by jifang on 15/12/9. */public class Sheep implements Cloneable {
private String name; private Date birthday; public Sheep() { } public Sheep(String name, Date birthday) { this.name = name; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "Sheep{" + "name='" + name + '\'' + ", birthday=" + birthday + '}'; } @Override protected Sheep clone() throws CloneNotSupportedException { return (Sheep) super.clone(); }}
  • Client
public class Client {    @Test    public void client() throws CloneNotSupportedException {        Date birthday = new Date();        Sheep mother = new Sheep("多利母亲", birthday);        System.out.println(mother);        Sheep dolly = mother.clone();        dolly.setName("多利");        System.out.println(dolly);    }}

浅复制与深复制

  • 浅复制
    在上面的Client上添加几行代码, 就可以发现问题:
@Testpublic void client() throws CloneNotSupportedException {    Date birthday = new Date();    Sheep mother = new Sheep("多利母亲", birthday);    System.out.println(mother);    Sheep dolly = mother.clone();    dolly.setName("多利");    System.out.println(dolly);    birthday.setTime(123123123123L);    System.out.println("dolly birthday: " + dolly.getBirthday());}

运行上面的代码我们可以看到更改了mother的birthday, dolly的birthday也更改了. 这个问题是由浅复制引起的.

浅复制:

创建当前对象的浅复制版本, 方法是创建一个新对象, 然后将当前对象的非静态字段复制到该新对象. 如果字段是值类型, 则对该字段执行逐位复制; 如果字段是引用类型, 则复制引用但不复制引用的对象; 因此原始对象及其副本引用同一对象;

此时运行的内存简化图如下:

可以看到mother和dolly的birthday指向同一个date对象.

  • 深复制版本
    深复制: 把引用对象的变量指向
    复制过来的新对象, 而不是原有的被引用的对象;
@Overrideprotected Sheep clone() throws CloneNotSupportedException {    Sheep sheep = (Sheep) super.clone();    // 添加下面代码支持深复制    sheep.birthday = (Date) this.birthday.clone();    return sheep;}

因此我们把Sheep的clone方法改成上面实现后, 再调用client方法就不会出现问题了, 此时的内存简图如下:

  • 利用序列化实现深复制
    Sheep需要先实现Serializable接口.
@Overrideprotected Sheep clone() throws CloneNotSupportedException {    ByteArrayOutputStream bos = new ByteArrayOutputStream();    try {        ObjectOutputStream oos = new ObjectOutputStream(bos);        oos.writeObject(this);        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));        return (Sheep) ois.readObject();    } catch (IOException e) {        e.printStackTrace();    } catch (ClassNotFoundException e) {        e.printStackTrace();    }    return null;}

原型模式性能测试

假设创建Sheep是比较耗时的, 在此基础上进行原型模式的额性能测试:

/** * 模拟耗时的对象创建过程 * * @param name * @param birthday */public Sheep(String name, Date birthday) {    try {        Thread.sleep(10);    } catch (InterruptedException e) {        e.printStackTrace();    }    this.name = name;    this.birthday = birthday;}
  • 测试Client
public class Client {
private static final int OBJECT_COUNT = 1000; private long testNew() { long start = System.currentTimeMillis(); for (int i = 0; i < OBJECT_COUNT; ++i) { Sheep sheep = new Sheep("name", new Date()); } return System.currentTimeMillis() - start; } private long testPrototype() throws CloneNotSupportedException { long start = System.currentTimeMillis(); Sheep sheep = new Sheep("name", new Date()); for (int i = 0; i < OBJECT_COUNT; ++i) { Sheep newSheep = sheep.clone(); newSheep.setName("new name"); } return System.currentTimeMillis() - start; } @Test public void client() throws CloneNotSupportedException { System.out.println(testNew()); System.out.println(testPrototype()); }}

运行上面程序, 可以很明显看出new与原型模式的性能差异, 如果吧Sheep构造器中的sleep注释掉, new与clone虽然有差异, 但是差距较小.

应用场景:

  • 原型模式很少单独出现, 一般都是与工厂方法模式一起出现, 通过clone方法创建一个对象, 然后由工厂返回给调用者. 像Spring中的Bean的创建模式就有singleton与prototype模式.

参考:

转载地址:http://eijko.baihongyu.com/

你可能感兴趣的文章
zoom和transform:scale的区别
查看>>
幸福框架:可扩展的、动态的、万能的 编号生成器
查看>>
黄聪:PHP 防护XSS,SQL,代码执行,文件包含等多种高危漏洞
查看>>
svn status 显示 ~xx
查看>>
常用HiveQL总结
查看>>
[转]使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(三)-- Logger
查看>>
POJ 3311 Hie with the Pie(状压DP + Floyd)
查看>>
HDU 1402 A * B Problem Plus FFT
查看>>
Security updates and resources
查看>>
深入理解JavaScript系列(25):设计模式之单例模式
查看>>
DNS为什么通常都会设置为14.114.114.114
查看>>
给定一个序列,判断该序列是否为二叉树查找树的后序遍历序列
查看>>
Sqoop架构(四)
查看>>
golang copy函数
查看>>
《你有多少问题要请示》精华集粹
查看>>
深度 | 机器学习敲门砖:任何人都能看懂的TensorFlow介绍【转】
查看>>
leveldb学习:DBimpl
查看>>
[Recompose] Stream Props to React Children with RxJS
查看>>
打印图片
查看>>
SHOW CREATE DATABASE Syntax
查看>>