zoukankan      html  css  js  c++  java
  • Java 原型模式(克隆模式)

      Java 的设计模式有 23 种,前段时间小编已经介绍了单例模式,由于我们在学习 Spring 的时候在 bean 标签的学习中碰到了今天要讲的原型模式,那么小编就已本文来介绍下原型模式。

    原型模式
      在java中我们知道通过new关键字创建的对象是非常繁琐的(类加载判断,内存分配,初始化等),在我们需要大量对象的情况下,原型模式就是我们可以考虑实现的方式。
      原型模式我们也称为克隆模式,即一个某个对象为原型克隆出来一个一模一样的对象,该对象的属性和原型对象一模一样。而且对于原型对象没有任何影响。原型模式的克隆方式有两种:浅克隆和深度克隆

    浅克隆
      在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

      简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。


    实现
    被克隆的对象必须Cloneable,Serializable这两个接口
    原型类

    /**
    * 原型类:被克隆的类型
    */
    public class User implements Cloneable, Serializable {

    private String name;

    private Date birth;

    private int age;

    /**
    * 实现克隆的方法
    * @return
    * @throws CloneNotSupportedException
    */
    public Object clone() throws CloneNotSupportedException {
    return super.clone();
    }
    //此处略过get和set方法
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    测试类

    public static void main(String[] args) throws CloneNotSupportedException {
    Date date = new Date(1231231231231l);
    User user = new User();
    user.setName("zmf");
    user.setAge(18);
    user.setBirth(date);
    System.out.println("----输出原型对象的属性------");
    System.out.println(user);
    System.out.println(user.getName());
    System.out.println(user.getBirth());
    // 克隆对象
    User user1 =(User) user.clone();
    // 修改原型对象中的属性
    date.setTime(123231231231l);
    System.out.println("原型对象修改后的属性:" + user.getBirth());

    // 修改参数
    user1.setName("知性人");
    System.out.println("-------克隆对象的属性-----");
    System.out.println(user1);
    System.out.println(user1.getName());
    System.out.println(user1.getBirth());
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    输出结果:

    ----输出原型对象的属性------
    org.zmf.User@1b6d3586
    zmf
    Tue Jan 06 16:40:31 CST 2009
    原型对象修改后的属性:Tue Nov 27 14:53:51 CST 1973
    -------克隆对象的属性-----
    org.zmf.User@14ae5a5
    知性人
    Tue Nov 27 14:53:51 CST 1973
    1
    2
    3
    4
    5
    6
    7
    8
    9
    说明:克隆后的 date 属性和原型对象修改后的 date 属性的结果一样 说明两个对象的Date的引用是同一个。由此可以说明,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

    深克隆
      在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

      简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。


    深度克隆(deep clone)有两种实现方式,第一种是在浅克隆的基础上实现,第二种是通过序列化和反序列化实现,我们分别来介绍
    1
    第一种方式
    在浅克隆的基础上实现
    原型类

    /**
    * 原型类:被克隆的类型
    * 深度克隆测试
    */
    public class User2 implements Cloneable, Serializable {

    private String name;

    private Date birth;

    private int age;

    /**
    * 实现克隆的方法
    * 深度克隆(deep clone)
    */
    public Object clone() throws CloneNotSupportedException{
    Object object = super.clone();
    // 实现深度克隆(deep clone)
    User2 user = (User2)object;
    user.birth = (Date) this.birth.clone();
    return object;
    }
    //此处略过 get 和 set 方法
    }
    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
    测试类:

    public static void main(String[] args) throws CloneNotSupportedException {
    Date date = new Date(1231231231231l);
    User2 user = new User2();
    user.setName("zmf");
    user.setAge(18);
    user.setBirth(date);
    System.out.println("----输出原型对象的属性------");
    System.out.println(user);
    System.out.println(user.getName());
    System.out.println(user.getBirth());
    // 克隆对象
    User2 user1 =(User2) user.clone();
    // 修改原型对象中的属性
    date.setTime(123231231231l);
    System.out.println("原型对象修改后的属性:" + user.getBirth());
    // 修改参数
    user1.setName("知性人");
    System.out.println("-------克隆对象的属性-----");
    System.out.println(user1);
    System.out.println(user1.getName());
    System.out.println(user1.getBirth());

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    测试结果:

    ----输出原型对象的属性------
    org.zmf.User2@1b6d3586
    zmf
    Tue Jan 06 16:40:31 CST 2009
    原型对象修改后的属性:Tue Nov 27 14:53:51 CST 1973
    -------克隆对象的属性-----
    org.zmf.User2@14ae5a5
    知性人
    Tue Jan 06 16:40:31 CST 2009
    1
    2
    3
    4
    5
    6
    7
    8
    9
    说明:根据测试得出克隆后的对象的属性并没有随着我们对原型对象Date属性的修改而改变,说明克隆对象的Date属性和原型对象的Date属性引用的不是同一个对象,实现的深度复制。

    第二种方式:序列化和反序列化
    说明
    序列化: 把对象转换为字节序列的过程。
    反序列化: 把字节序列恢复为对象的过程。
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
    Date date = new Date(1231231231231L);
    User user = new User();
    user.setName("zmf");
    user.setAge(18);
    user.setBirth(date);
    System.out.println("-----原型对象的属性------");
    System.out.println(user);
    System.out.println(user.getName());
    System.out.println(user.getBirth());

    //使用序列化和反序列化实现深复制
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(user);
    byte[] bytes = bos.toByteArray();

    ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
    ObjectInputStream ois = new ObjectInputStream(bis);

    //克隆好的对象!
    User user1 = (User) ois.readObject();

    // 修改原型对象的值
    date.setTime(221321321321321L);
    System.out.println(user.getBirth());

    System.out.println("------克隆对象的属性-------");
    System.out.println(user1);
    System.out.println(user1.getName());
    System.out.println(user1.getBirth(http://www.my516.com));
    }
    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
    测试结果:

    -----原型对象的属性------
    org.zmf.User@1b6d3586
    zmf
    Tue Jan 06 16:40:31 CST 2009
    Sat May 24 16:48:41 CST 8983
    ------克隆对象的属性-------
    org.zmf.User@5f184fc6
    zmf
    Tue Jan 06 16:40:31 CST 2009
    1
    2
    3
    4
    5
    6
    7
    8
    9
    实现了和第一种实现方式相同的效果~实现了深度克隆

    总结
    实现对象克隆有两种方式:

     1). 实现Cloneable接口并重写Object类中的clone()方法;

     2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
    ---------------------

  • 相关阅读:
    看看自己敲了多少代码
    jquery中获取单选标签redio的val
    @functools.wrapes
    SQLAlachemy 自动提交配置 SQLALCHEMY_COMMIT_ON_TEARDOWN
    ajax 常用格式
    开发文档收藏
    falsk 请求钩子
    数组中出现次数超过数组长度一半的值 分类: C/C++ 2015-07-09 15:38 142人阅读 评论(0) 收藏
    二叉搜索树(C++) 分类: C/C++ 数据结构与算法 2015-07-09 11:18 205人阅读 评论(0) 收藏
    程序员必读的六本书 2015-07-08 11:26 21人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/hyhy904/p/11082107.html
Copyright © 2011-2022 走看看