浅墨散人 浅墨散人
  • 基础
  • 设计模式
  • JVM
  • Maven
  • SpringBoot
  • 基础
  • Flask
  • Diango
  • Pandas
  • SqlAlchemy
  • Sqoop
  • Flume
  • Flink
  • Hadoop
  • Hbase
  • Hive
  • Kafka
  • Kylin
  • Zookeeper
  • Tez
  • MySQL
  • Doris
  • Chrome
  • Eclipse
  • IDEA
  • iTerm2
  • Markdown
  • SublimeText
  • VirtualBox
  • WebStrom
  • Linux
  • Mac
  • Hexo
  • Git
  • Vue
  • VuePress
  • 区块链
  • 金融
数据仓库
数据治理
读书笔记
关于我
GitHub (opens new window)
  • 基础
  • 设计模式
  • JVM
  • Maven
  • SpringBoot
  • 基础
  • Flask
  • Diango
  • Pandas
  • SqlAlchemy
  • Sqoop
  • Flume
  • Flink
  • Hadoop
  • Hbase
  • Hive
  • Kafka
  • Kylin
  • Zookeeper
  • Tez
  • MySQL
  • Doris
  • Chrome
  • Eclipse
  • IDEA
  • iTerm2
  • Markdown
  • SublimeText
  • VirtualBox
  • WebStrom
  • Linux
  • Mac
  • Hexo
  • Git
  • Vue
  • VuePress
  • 区块链
  • 金融
数据仓库
数据治理
读书笔记
关于我
GitHub (opens new window)
  • 设计模式

    • Java设计模式
    • 享元模式(FlyWeight)
    • 代理模式(Proxy)
    • 单例模式(Singleton)
    • 原型模式(Prototype)
      • ​一、原型模式介绍
      • 二、代码实现
        • 1、浅克隆代码实现:
        • 2、深克隆代码实现:克隆对象的同时,把该对象的属性也连带着克隆出新的。
        • 3、通过序列化和反序列化来实现深克隆对象:
      • 三、测试克隆对象的效率
      • 四、使用场景
    • 外观模式(Facade)
    • 工厂模式(Factory)
    • 建造者模式(Builder和Director)
    • 桥接模式(Bridge)
    • 组合模式(Composite)
    • 装饰器模式(Decorator)
    • 适配器模式(Adpater)
  • Java
  • DesignPattern
2016-03-29
目录

原型模式(Prototype)

# ​一、原型模式介绍

原型模式:原型模式就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。 所谓原型模式,就是java中的克隆技术,以某个对象为原型。复制出新的对象。显然新的对象具备原型对象的特点。效率高(避免了重新执行构造过程步骤) 克隆类似于new,但和new不同。new创建新的对象属性采用的是默认值。克隆出来的对象的属性值完全和原型对象相同。并且克隆出的新对象不会影响原型对象,克隆后。还可以再修改克隆对象的值。 要实现原型模式,必须实现Cloneable接口,而这个接口里面是空的。 Cloneable接口是一个空接口,使用Cloneable接口都不用导入包。而clone方法是属于Object对象的。如果要克隆某个对象的话必须实现Cloneable接口

* @author  unascribed
 * @see     java.lang.CloneNotSupportedException
 * @see     java.lang.Object#clone()
 * @since   JDK1.0
 */
public interface Cloneable {
}
1
2
3
4
5
6
7

重写Object对象的clone方法,clone方法为本地方法。效率比较高

protected native Object clone() throws CloneNotSupportedException;
1

如果我们要克隆某个对象有浅克隆和深克隆 浅克隆:copy该对象,然后保留该对象原有的引用。也就是说不克隆该对象的属性。 深克隆:copy该对象,并且把该对象的所有属性也克隆出一份新的。

# 二、代码实现

# 1、浅克隆代码实现:

/**
 * 原型模式:浅克隆
 * Cloneable是一个空接口(标记接口),是一个规范。但是如果要克隆这个类对象的话必须实现Cloneable接口
 */
public class Sheep implements Cloneable{
    private String sname;
    private Date birthday;
    /**
     * 重写Object对象的clone方法
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //直接调用Object对象的clone方法
        Object obj = super.clone();
        return obj;
    }
    //省略get,set方法和构造方法
}
/**
 * 测试原型模式(浅克隆)
 */
public class Test {
    public static void main(String[] args) throws Exception {
        Date date = new Date(1274397294739L);
        Sheep s1 = new Sheep("原型羊",date);
        Sheep s2 = (Sheep) s1.clone();//克隆一个羊
        System.out.println(s1);
        System.out.println(s1.getSname());
        System.out.println("原日期:"+s1.getBirthday());
        date.setTime(34732834827389L);//改变原有date的值
        System.out.println("改变后的日期:"+date.toString());
        //克隆羊的信息
        System.out.println("---------------------------------");
        System.out.println(s2);
        System.out.println(s2.getSname());
        System.out.println(s2.getBirthday());//此时的birthday日期使用的是改变后的日期对象引用
    }
}
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

最后的结果为:克隆的对象仍然保留了原有对象的引用,值随着改变而改变

com.fz.prototype.Sheep@153f67e
原型羊
原日期:Fri May 21 07:14:54 CST 2010
改变后的日期:Mon Aug 22 17:40:27 CST 3070
---------------------------------
com.fz.prototype.Sheep@18f51f
原型羊
Mon Aug 22 17:40:27 CST 3070
1
2
3
4
5
6
7
8

# 2、深克隆代码实现:克隆对象的同时,把该对象的属性也连带着克隆出新的。

深克隆只需要在clone方法中将该对象的属性也克隆即可

/**
 * 重写Object对象的clone方法
 */
@Override
protected Object clone() throws CloneNotSupportedException {
    //直接调用Object对象的clone方法
    Object obj = super.clone();
    //深克隆:把对象下的所有属性也克隆出来
    Sheep22 s = (Sheep22) obj;
    s.birthday = (Date) this.birthday.clone();
    return s;
}
1
2
3
4
5
6
7
8
9
10
11
12

测试代码不变,结果则会变了。克隆了之后把原来的日期改变后,克隆的对象2的属性则不会被影响。

com.fz.prototype.Sheep2@15bdc50
原型羊
原日期:Fri May 21 07:14:54 CST 2010
改变后的日期:Mon Aug 22 17:40:27 CST 3070
---------------------------------
com.fz.prototype.Sheep2@18f51f
原型羊
Fri May 21 07:14:54 CST 2010
1
2
3
4
5
6
7
8

# 3、通过序列化和反序列化来实现深克隆对象:

序列化需要原型对象实现Serializable接口

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
/**
 * 测试原型模式(利用序列化和反序列化实现深克隆)
 */
public class Test3 {
    public static void main(String[] args) throws Exception {
        Date date = new Date(1274397294739L);
        Sheep s1 = new Sheep("原型羊",date);
//      Sheep s2 = (Sheep) s1.clone();//克隆一个羊
        //使用序列化和反序列化实现深复制
        //1、将s1对象序列化为一个数组
        //通过ObjectOutputStream流将s1对象读出来给ByteArrayOutputStream流
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream    oos = new ObjectOutputStream(bos);
        oos.writeObject(s1);
        //ByteArrayOutputStream流将对象信息转成byte数组,这样byte数组里就包含了对象的数据
        byte[] bytes = bos.toByteArray();
        //2、将字节数组中的内容反序列化为一个Sheep对象
        //通过ByteArrayInputStream流读入bytes字节数组中数据,然后传给ObjectInputStream对象输入流
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        ObjectInputStream    ois = new ObjectInputStream(bis);
        //通过ObjectInputStream返回一个Sheep对象
        Sheep s2 = (Sheep) ois.readObject();
        //原型羊的信息
        System.out.println(s1);
        System.out.println("原日期:"+s1.getBirthday());
        date.setTime(34732834827389L);//改变原有date的值
        System.out.println("改变后的日期:"+date.toString());
        //克隆羊的信息
        System.out.println("---------------------------------");
        System.out.println(s2);
        System.out.println(s2.getBirthday());
    }
}
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

通过序列化和反序列化的结果,最终结果还是和深克隆一样。

com.fz.prototype.Sheep@1a116c9
原日期:Fri May 21 07:14:54 CST 2010
改变后的日期:Mon Aug 22 17:40:27 CST 3070
---------------------------------
com.fz.prototype.Sheep@7eb6e2
Fri May 21 07:14:54 CST 2010
1
2
3
4
5
6

# 三、测试克隆对象的效率

package com.fz.prototype;
/**
 * 测试clone对象的效率
 */
public class TestClone {
    //new 对象
    public static void testNew(int size){
        long start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            Laptop l = new Laptop();
        }
        long end = System.currentTimeMillis();
        System.out.println("new 对象耗时:"+(end-start));
    }
    //clone 对象
    public static void testClone(int size){
        long start = System.currentTimeMillis();
        Laptop l = new Laptop();
        for (int i = 0; i < size; i++) {
            try {
                Laptop temp = (Laptop) l.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("clone 对象耗时:"+(end-start));
    }
    public static void main(String[] args) {
        testNew(1000);
        testClone(1000);
    }
}
class Laptop implements Cloneable{
    public Laptop() {
        //模拟创建Laptop对象的时候比较耗时
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.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

最后结果为: new 对象耗时:10063 clone 对象耗时:10

# 四、使用场景

原型模式适用场景:如果某个对象new的过程中很耗时,则可以考虑使用原型模式。 Spring框架中bean对象的创建就两种模式:单例模式或者原型模式

#java#设计模式
最后更新时间: 2022/7/23 10:17:11
单例模式(Singleton)
外观模式(Facade)

← 单例模式(Singleton) 外观模式(Facade)→

最近更新
01
分区分桶
08-21
02
数据模型(重要)
08-21
03
安装和编译
08-21
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式