结合JDK源码看设计模式——原型模式

定义:

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

  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快,知道深克隆,但是具体的还是看业务场景的需求,希望能多理解适用场景的那几种情况。

(0)

相关推荐

  • 五分钟 掌握 原型模式 (文末送书)

    回复"000"获取程序员必备电子书 大家好,我是老田,今天我给大家分享设计模式中的原型模式.用贴切的生活故事,以及真实项目场景来讲设计模式,最后用一句话来总结这个设计模式. 关于设 ...

  • 面试官:你知道对象的克隆原理吗?

    本文主要内容 背景 先说说生活中三个例子: 西游记中,孙悟空能变身为n多个孙悟空,也就是一个孙悟空克隆为多个孙悟空了. 王者农药中,元歌有个傀儡,这个傀儡我们也可理解为复制的元歌,你把傀儡杀死了,其实 ...

  • PrototypePattern原型模式

    原型模式 1.定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 Java自带一个Cloneable接口,原型类实现该接口并重写clone方法,通过调用该方法创建新的对象.这种不通过 ...

  • 设计模式-原型模式

    原型模式 ​原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,并且通过拷贝这些原型创建新的对象 ​调用者不需要知道任何创建细节,不调用构造函数 ​其属于一种创建型模式 通用类图 优点 性能 ...

  • 创建型模式之原型模式

    定义与特点 原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象. 在这里,原型实例指定了要创建的对象的种类.用这种方式创建对象 ...

  • 原型模式

    序言:今天我们来聊一下原型模式,我个人认为原型模式的命名不太好理解,称呼其为克隆模式会更妥当一点.原型模式的目的是通过复制一个现有的对象来生成一个新的对象,而不是通过实例化的方法. 原型模式的基本介绍 ...

  • PHP设计模式之原型模式

    PHP设计模式之原型模式 原型模式其实更形象的来说应该叫克隆模式.它主要的行为是对对象进行克隆,但是又把被克隆的对象称之为最初的原型,于是,这个模式就这样被命名了.说真的,从使用方式来看真的感觉叫克隆 ...

  • 设计模式-原型模式详解

    一.原型模式的概念 原型模式属于创建型设计模式.当要创建的对象类型由原型实例确定时使用它,该实例被克隆以生成新对象. 此模式用于 1.避免客户端应用程序中的对象创建者的子类,如工厂方法模式. 2.避免 ...

  • 所有类的父类 Java Object

    Java Object 一.什么是Java Object 二.Object类的方法 1.创建并返回一个对象的拷贝protected Object clone() 2.比较两个对象是否相等 boolea ...

  • 大白话原型模式(Prototype Pattern)

    意图 原型模式是创建型设计模式,可以复制已存在的对象而无需依赖它的类. 问题 假如现在有一个对象,我们想完全复制一份新的,我们该如何做? 创建同一个类的新对象 遍历所有已存在对象的值,然后将他们的值复 ...