定义:

  指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。不需要知道任何创建的细节,不调用构造函数
适用场景:

  1. 类初始化的时候消耗较多资源
  2. new产生的对象需要非常繁琐的过程
  3. 构造函数比较复杂
  4. 循环体中产生大量对象

详解:
  接下来我们分下面几部分讲解:

  1. 原型模式的核心
  2. 深克隆和浅克隆
  3. JDK源码分析

1.原型模式的核心

  其实很简单,就是实现Cloneable接口,然后重写clone()方法。上面我们已经说过 ,当你在上面的适用场景中的时候,按照我们平常的办法来说肯定是直接new对象出来,但是new对象特别多的时候就会消耗很多资源,并且效率也是比较缓慢的。所以我们引入原型模式的情况,其实我们只需要创建出一个原型来 ,剩下的完全可以通过克隆来达到创建新对象的目的。克隆是底层直接拿二进制流来克隆出新对象,然后对新对象进行特别的操作。
2.深克隆和浅克隆
这时候你心里可能会有疑惑,克隆不就克隆就行了吗?怎么还分浅克隆和深克隆。事实上在一个类中如果有另外的类的实例作为属性的话,正常使用Object.clone()方法,这个对象成员是无法被克隆的,也就是浅克隆。所以你怎么改原型中的对象成员,后面克隆的版本中这个对象成员就会一直跟原型一样。但是我们的目标是创建新对象来进行特定的操作,也就是希望每个对象里面的值不会跟他人共享。新对象是新对象,原型是原型。所以我们需要深克隆。下面我举几个例子来看看

public class Student implements Cloneable{
private int age;
private Date date;
private String name; public void setAge(int age) {
this.age = age;
} public void setDate(Date date) {
this.date = date;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Student{" +
"age=" + age +
", date=" + date +
", name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

  然后我们写一下测试类

class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student stu=new Student();
Student stu1= (Student) stu.clone();
Date date=new Date(0L);
int i=10;
stu.setDate(date);
stu1.setDate(date);
stu.setAge(i);
stu1.setAge(i);
System.out.println(stu);
System.out.println(stu1);
date.setTime(666666666L);
stu.setDate(date);
i=11;
stu.setAge(i);
System.out.println(stu);
System.out.println(stu1);
}
}

最终输出结果就是

分析一下

注意看这4行,我们上面是两个都调用了set方法,下面只有stu原型调用了set方法,但是最终却两个对象中的值一起改了。可能细心的的注意到Age只有stu改了,这是因为int类型基本数据类型。而Date类型的对象成员就不行了,实际上只有Student这个类进行了克隆,但是Student里面的对象成员变量没有进行克隆。所以那个对象还是那个对象。

上面就是浅克隆。要想做到深克隆,可以在clone方法里面clone出对应的对象成员结果及代码如下

  上面我重写了clone()方法,实现了深克隆
3.JDK源码解析
  其实我们主要理解拷贝原型来创建新的对象,拷贝是比new更快的一个创建对象的方法,当你需要大批量创建新对象而且都是同一个类的对象的时候可以考虑用原型模式。但是千万千万注意就是一般的克隆只是浅克隆(浅克隆:只是对象的hash值不一样,但是对象里面的对象成员变量的hash值是一样的)有些场景可能是需要我们深克隆的,这时候就需要我们重写Object.clone()方法。就拿ArrayList中的clone()方法来看

public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();//先克隆出一个ArrayList
v.elementData = Arrays.copyOf(elementData, size);//将原型中的数据拷贝到新的ArrayList中
v.modCount = 0;//把修改次数改为0
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}

  相信看懂了上面的实例,你也能理解ArrayList中这段代码到底是做什么
总结:
  尽管我们会用了原型,知道拷贝比new快,知道深克隆,但是具体的还是看业务场景的需求,希望能多理解适用场景的那几种情况。

结合JDK源码看设计模式——原型模式的更多相关文章

  1. 结合JDK源码看设计模式——桥接模式

    前言: 在我们还没学习框架之前,肯定都学过JDBC.百度百科对JDBC是这样介绍的[JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Jav ...

  2. 结合JDK源码看设计模式——模板方法模式

    前言: 相信很多人都听过一个问题:把大象关进冰箱门,需要几步? 第一,把冰箱门打开:第二,把大象放进去:第三,把冰箱门关上.我们可以看见,这个问题的答案回答的很有步骤.接下来我们介绍一种设计模式--模 ...

  3. 结合JDK源码看设计模式——迭代器模式

    前言: Iterator翻译过来就是迭代器的意思.在前面的工厂模式中就介绍过了iterator,不过当时介绍的是方法,现在从Iterator接口的设计来看,似乎又是一种设计模式,下面我们就来讲讲迭代器 ...

  4. 结合JDK源码看设计模式——建造者模式

    概念: 将一个复杂对象的构建与它的表示分离.使得同样构建过程可以创建不同表示适用场景: 一个对象有很多属性的情况下 想把复杂的对象创建和使用分离 优点: 封装性好,扩展性好 详解: 工厂模式注重把这个 ...

  5. 结合JDK源码看设计模式——策略模式

    前言: 现在电商已经成为我们生活中不可或缺的购物渠道,同时各大商家会针对不同的时间做出不同的折扣,这在我们看来就是一种营销手段,也是一种策略,今天我们就来讲讲JDK中的策略模式是怎么样的. 一.定义 ...

  6. 结合JDK源码看设计模式——组合模式

    前言: 相信大家都打开过层级很多很多的文件夹.如果把第一个文件夹看作是树的根节点的话,下面的子文件夹就可以看作一个子节点.不过最终我们寻找的还是文件夹中的文件,文件可以看做是叶子节点.下面我们介绍一种 ...

  7. 结合JDK源码看设计模式——单例模式

    定义: 保证一个类仅有一个实例,并提供一个全局访问点 适用场景: 确保任何情况下这个对象只有一个实例 详解: 私有构造器 单利模式中的线程安全+延时加载 序列化和反序列化安全, 防止反射攻击 结合JD ...

  8. 结合JDK源码看设计模式——简单工厂、工厂方法、抽象工厂

    三种工厂模式的详解: 简单工厂模式: 适用场景:工厂类负责创建的对象较少,客户端只关心传入工厂类的参数,对于如何创建对象的逻辑不关心 缺点:如果要新加产品,就需要修改工厂类的判断逻辑,违背软件设计中的 ...

  9. 结合JDK源码看设计模式——享元模式

    前言 在说享元模式之前,你一定见到过这样的面试题 public class Test { public static void main(String[] args) { Integer a=Inte ...

随机推荐

  1. Hello Django

    首先安装Django: 1.cmd界面,输入"pip3 install django" 2.输入"django-admin help",如下图表示安装成功   ...

  2. 如何书写一篇能看懂的html和CSS代码

    在书写html和CSS过程中,如果只是想要实现网页的外观和基本功能,那么简单的书写代码就可以满足需求,甚至不需要使用类名或者注释等.但实际上,这么写肯定是不行的,首先对于类同结构的重复书写就是一件很浪 ...

  3. Win32项目生成的程序exe图标显示异常的问题

    问题 如图: 用VS2013生成exe执行文件时发现的问题,起初以为是没添加ico图像的最小尺寸,后来查看ico并不是这个问题. Baidu.Google了半天找到原因:文件资源管理器的图标缓存bug ...

  4. Oracle 服务启动关闭

    有没有感觉到,自从装上Oracle之后,电脑变卡了?卡是正常的,oracle作为大型数据库软件,运行起来是非常吃内存的. 所以对于自用的电脑来说,不使用Oracle的时候,应该把Oracle的一系列服 ...

  5. mysql的内建日期处理函数

    下面的表格列出了MySQL 中最重要的内建日期函数: 函数 描述 NOW() 返回当前的日期和时间 CURDATE() 返回当前的日期 CURTIME() 返回当前的时间 DATE() 提取日期或日期 ...

  6. SHELL脚本--expr命令全解

    bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html expr命令可以实现数值运算.数值或字符串比较.字符串匹配.字 ...

  7. 第四章——训练模型(Training Models)

    前几章在不知道原理的情况下,已经学会使用了多个机器学习模型机器算法.Scikit-Learn很方便,以至于隐藏了太多的实现细节. 知其然知其所以然是必要的,这有利于快速选择合适的模型.正确的训练算法. ...

  8. OAuth 2.0 认证的原理与实践

    摘要: 使用 OAuth 2.0 认证的的好处是显然易见的.你只需要用同一个账号密码,就能在各个网站进行访问,而免去了在每个网站都进行注册的繁琐过程. 本文将介绍 OAuth 2.0 的原理,并基于 ...

  9. ES7 Async/Await 陷阱

    什么是Async/Await ES6新增了Promise函数用于简化项目代码流程.然而在使用promise时,我们仍然要使用callback,并且并不知道程序要干什么,例如: function doS ...

  10. Windows下SVN命令行工具使用详解

    根据我的记忆,似乎Windows 7下自自带一个svn命令行工具.如果你的机器没有,不必担心.你可以从http://subversion.tigris.org获 取subversion for win ...