zoukankan      html  css  js  c++  java
  • 设计模式之原型模式

    原型模式,即Prototype,是指创建新对象的时候,根据现有的一个原型来创建。

    1. 原型模式

    原型模式(Prototype)比较类似于复制粘贴的思想,它可以首先创建一个实例,然后通过这个实例进行新对象的创建。在 Java 中,最典型的就是 Object 类的 clone 方法。

    但编码中这个方法很少用,我们在代理模式提到的 prototype,并不是通过 clone 实现的,而是使用了更复杂的反射技术。

    一个比较重要的原因就是 clone 如果只拷贝当前层次的对象,实现的只是浅拷贝。在现实情况下,对象往往会非常复杂,想要实现深拷贝的话,需要在 clone 方法里做大量的编码,远远不如调用 new 方法方便。

    实现深拷贝,还有序列化等手段,比如实现 Serializable 接口,或者把对象转化成 JSON。

    所以,在现实情况下,原型模式变成了一种思想,而不是加快对象创建速度的工具。

    使用的时候,因为clone()的方法签名是定义在Object中,返回类型也是Object,所以要强制转型,比较麻烦:

    Student student = new Student();
    student.setName("li");
    Student student2 = (Student)student.clone();
    
    System.out.print(student==student2); //  false
    

    实际上,使用原型模式更好的方式是定义一个copy()方法,返回明确的类型:

    public class Student {
        private int id;
        private String name;
        private int score;
    
        public Student copy() {
            Student std = new Student();
            std.id = this.id;
            std.name = this.name;
            std.score = this.score;
            return std;
        }
    }
    

    原型模式应用不是很广泛,因为很多实例会持有类似文件、Socket这样的资源,而这些资源是无法复制给另一个对象共享的,只有存储简单类型的“值”对象可以复制。

    2. Java中的浅拷贝和深拷贝

    2.1 引用拷贝

    创建一个指向对象的引用变量的拷贝。

    Teacher teacher = new Teacher("Taylor",26);
    Teacher otherteacher = teacher;
    System.out.println(teacher);
    System.out.println(otherteacher);
    
    结果:
    blog.Teacher@355da254
    blog.Teacher@355da254
    

    结果分析:由输出结果可以看出,它们的地址值是相同的,那么它们肯定是同一个对象。teacher和otherteacher的只是引用而已,他们都指向了一个相同的对象Teacher(“Taylor”,26)。 这就叫做引用拷贝。

    2.2 对象拷贝

    创建对象本身的一个副本。

    Teacher teacher = new Teacher("Swift",26);
    Teacher otherteacher = (Teacher)teacher.clone();
    System.out.println(teacher);
    System.out.println(otherteacher);
    
    结果
    blog.Teacher@355da254
    blog.Teacher@4dc63996
    

    结果分析:由输出结果可以看出,它们的地址是不同的,也就是说创建了新的对象, 而不是把原对象的地址赋给了一个新的引用变量,这就叫做对象拷贝。

    深拷贝和浅拷贝都是对象拷贝

    2.3 浅拷贝

    被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。"里面的对象“会在原来的对象和它的副本之间共享。

    简而言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象

    2.4 深拷贝

    深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。

    简而言之,深拷贝把要复制的对象所引用的对象都复制了一遍

    2.5 通过序列化进行深拷贝

    public Object deepClone() throws Exception {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
    
            oos.writeObject(this);
    
            // 反序列化
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
    
            return ois.readObject();
        }
    

    References

  • 相关阅读:
    BZOJ 2212/BZOJ 3702
    BZOJ 4761 Cow Navigation
    BZOJ 3209 花神的数论题
    BZOJ 4760 Hoof, Paper, Scissors
    BZOJ 3620 似乎在梦中见过的样子
    BZOJ 3940 Censoring
    BZOJ 3942 Censoring
    BZOJ 3571 画框
    BZOJ 1937 最小生成树
    BZOJ 1058 报表统计
  • 原文地址:https://www.cnblogs.com/wei57960/p/14691176.html
Copyright © 2011-2022 走看看