美文网首页架构与设计模式
原型模式及深浅拷贝详解

原型模式及深浅拷贝详解

作者: 咋家 | 来源:发表于2020-03-23 10:38 被阅读0次

    原型模式

    原型模式(Prototype模式)是用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。

    原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。其工作原理是通过将一个原型对象传给要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它自己来实施创建。

    1、原理结构图

    其通用UML图如下:

    • Prototype:原型类,声明一个克隆自己的接口
    • ConcretePrototype:具体的原型类,实现一个克隆自己的操作
    • Client:让一个原型对象克隆自己,从而创建一个新的对象

    下面通过Object对象自带的clone()方法实现克隆羊,代码如下:

    具体原型类:

    public class Sheep implements Cloneable {
        private String name;
        private int age;
    
        public Sheep(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Sheep{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        //克隆实例,通过clone完成
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Sheep sheep= (Sheep) super.clone();
    
            return sheep;
        }
    }
    

    客户端:

    public class Client {
        public static void main(String[] args) throws CloneNotSupportedException {
            Sheep sheep = new Sheep("tom", 1);
    
            Sheep sheep2 = (Sheep) sheep.clone();
            Sheep sheep3 = (Sheep) sheep.clone();
            System.out.println(sheep2+" "+sheep2.hashCode());
            System.out.println(sheep3+" "+sheep3.hashCode());
        }
    }
    

    注意,对于含有引用类型的对象,原生clone()方法实现的是浅拷贝

    下面我们详细介绍深浅拷贝及java实现深拷贝的两种方式。

    2、浅拷贝和深拷贝

    浅拷贝

    • 对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值拷贝,也就是将该属性值复制一份给新的对象
    • 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只将该成员变量的引用值(内存地址)复制一份给新的对象,实际上两个对象的成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量的值。

    深拷贝

    • 复制对象的所有基本数据类型的成员变量值
    • 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝。

    对于深拷贝有两种实现方式:

    • 方式1:重写clone方法来实现深拷贝
    • 方式2:通过对象序列化来实现深拷贝(推荐)

    3、深拷贝的两种实现

    代码如下:

    //引用对象
    public class DeepCopyTarget implements Serializable,Cloneable {
    
        private static final long serialVersionUID=1L;
    
        private String name;
        private int age;
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    //深拷贝
    public class DeepCopy implements Serializable,Cloneable {
        public String name;
        public DeepCopyTarget deepCopyTarget;//引用类型
    
        //深拷贝,方式1:重写clone方法
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Object deep=null;
            //1、首先完成基本数据类型的拷贝
            deep=super.clone();
            //2、对引用类型的属性进行单独处理
            DeepCopy deepCopy= (DeepCopy) deep;
            deepCopy.deepCopyTarget= (DeepCopyTarget) deepCopyTarget.clone();
    
            return deepCopy;
        }
    
        //深拷贝,方式2:通过序列化
        public Object deepclone(){
            //创建流对象
            ByteArrayOutputStream bos=null;
            ObjectOutputStream oos=null;
            ByteArrayInputStream bis=null;
            ObjectInputStream ois=null;
            try {
                //序列化
                bos=new ByteArrayOutputStream();
                oos=new ObjectOutputStream(bos);
                oos.writeObject(this);//将当前对象以对象流的方式输出
    
                //反序列化
                bis=new ByteArrayInputStream(bos.toByteArray());
                ois=new ObjectInputStream(bis);
                DeepCopy objCopy = (DeepCopy) ois.readObject();
    
                return objCopy;
            }catch (Exception e){
                System.out.println(e.getMessage());
                return null;
            }finally {
                //关闭流
                try {
                    bos.close();
                    bis.close();
                    oos.close();
                    ois.close();
                }catch (Exception e){
                    System.out.println(e.getMessage());
                }
            }
    
        }
    }
    

    4、原型模式的细节

    创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能提高效率。

    不用重新初始化对象,而是动态的获得对象运行时的状态。

    如果原始对象发生变化,其它克隆对象也会发生相应的变化,无需修改代码。

    缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改源代码,违背了ocp原则。

    往期回顾

    设计模式七大原则
    UML类图的六大关系
    八种单例模式分析
    由浅入深工厂模式

    更多精彩,关注“咋家”

    相关文章

      网友评论

        本文标题:原型模式及深浅拷贝详解

        本文链接:https://www.haomeiwen.com/subject/mmkjyhtx.html