小白必备之原型模式总结(浅克隆和深克隆)

举报
Code皮皮虾 发表于 2021/08/25 21:25:50 2021/08/25
【摘要】 小白必备之原型模式总结(浅克隆和深克隆)

原型模式-基本介绍

什么是原型模式? 克隆羊多利大家应该都知道,这其实可以理解为原型模式的一种体现即使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象!

在这里插入图片描述

  1. 原型模式(Prototype模式)是指:用原型实例指定创建对象地种类,并且通过拷贝这些原型,创建新的对象。
  2. 原型模式是一种创建型设计模式,允许一个对象再创建另一个可定制地对象,无需知道创建细节。
  3. 工作原理:通过一个原型对象传给要发动创建地对象,这个要发动创建地对象通过请求原型对象拷贝他们自己来实施创建,即 对象.clone()

原型模式分三个角色,抽象原型类,具体原型类,客户类。

抽象原型类(prototype): 它是声明克隆方法的接口,是所有具体原型类的公共父类,它可以是接口,抽象类甚至是一个具体的实现类。

具体原型类(concretePrototype): 它实现了抽象原型类中声明的克隆方法,在克隆方法中返回一个自己的克隆对象。

客户类(Client): 在客户类中,使用原型对象只需要通过工厂方式创建或者直接NEW(实例化一个)原型对象,然后通过原型对象的克隆方法就能获得多个相同的对象。由于客户端是针对抽象原型对象编程的所以还可以可以很方便的换成不同类型的原型对象!

传统方式

代码实现

public class Sheep {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + 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;
    }
}
public class Client {

    public static void main(String[] args) {
        Sheep sheep = new Sheep("皮皮虾", 3);

        Sheep sheep1 = new Sheep(sheep.getName(), sheep.getAge());
        Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge());

        System.out.println(sheep);
        System.out.println(sheep1);
        System.out.println(sheep2);
    }
}

运行结果
在这里插入图片描述

总结

  1. 优点是比较好理解,简单好操作。
  2. 在创建新对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低。
  3. 总是需要重新初始化对象,而不是动态地获取对象运行时地状态,不够灵活。

原型模式解决

Java中Object类是所有类地根类,Object类提供了一个clone()方法,该方法可以将一个Java对象复制一份,但是需要实现clone地Java类必须要实现一个接口Cloneable,该接口表示该类能够复制且具有复制地能力。

代码实现

public class Sheep implements Cloneable{
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + 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;
    }

    //重写clone方法
    @Override
    protected Object clone(){
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        }catch (Exception e) {
            //打印出错误信息
            System.out.println(e.getMessage());
        }
        return sheep;
    }
}
public class Client {

    public static void main(String[] args) {
        Sheep sheep = new Sheep("皮皮虾", 3);
        Sheep clone1 = (Sheep) sheep.clone(); //克隆
        Sheep clone2 = (Sheep) sheep.clone();

        System.out.println(sheep);
        System.out.println(clone1);
        System.out.println(clone2);
    }
}

运行结果
在这里插入图片描述

原型模式(浅克隆与深克隆)

浅克隆

浅拷贝:我们只拷贝对象中的基本数据类型(8种),如果是复杂的类型,(枚举,String,对象)就只复制对应的内存地址。

public class Sheep implements Cloneable{
    private String name;
    private int age;
    public Sheep friend; //对象

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + 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;
    }

    //重写clone方法(默认)
    @Override
    protected Object clone(){
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        }catch (Exception e) {
            //打印出错误信息
            System.out.println(e.getMessage());
        }
        return sheep;
    }
}
public class Client {

    public static void main(String[] args) {
        Sheep sheep = new Sheep("皮皮虾", 3);
        sheep.friend = new Sheep("皮皮虾2号",4);

        Sheep clone1 = (Sheep) sheep.clone(); //克隆
        Sheep clone2 = (Sheep) sheep.clone();

        System.out.println(sheep + "friend:" + sheep.friend.hashCode());
        System.out.println(clone1 + "friend:" + clone1.friend.hashCode());
        System.out.println(clone2 + "friend:" + clone2.friend.hashCode());
    }
}

运行结果
在这里插入图片描述
可以看见friend的hasCode是一样的,只是复制一份引用值继,进行引用传递,所以默认的clone方法是浅拷贝。

深克隆

深拷贝:不仅能拷贝基本数据类型,还能拷贝那些数组、容器、引用对象等。

深拷贝有两种实现方式,一为重写clone方法,二为通过对象序列化(Serialization)来实现,我们这里选择使用更为推荐的对象序列化方式来进行实现。

public class Sheep implements Serializable {
    private String name;
    private int age;
    //对象
    private SheepFriend sheepFriend;

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Sheep(String name, int age, SheepFriend sheepFriend) {
        this.name = name;
        this.age = age;
        this.sheepFriend = sheepFriend;
    }

    public SheepFriend getSheepFriend() {
        return sheepFriend;
    }

    public void setSheepFriend(SheepFriend sheepFriend) {
        this.sheepFriend = sheepFriend;
    }

    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;
    }


    //通过序列化和反序列化实现深拷贝
    protected Sheep friendClone(){
        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);
           return (Sheep)ois.readObject();
       }catch (Exception e) {
           e.printStackTrace();
           return null;
       }finally {
            //关闭流
           try {
               bos.close();
               oos.close();
               bis.close();
               ois.close();
           }catch (Exception e) {
               e.printStackTrace();
           }
       }
    }
}
public class SheepFriend implements Serializable {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public SheepFriend(String name) {
        this.name = name;
    }
}
public class Client {

    public static void main(String[] args) {
        SheepFriend sheepFriend = new SheepFriend("Code皮皮虾");
        Sheep sheep = new Sheep("皮皮虾", 3,sheepFriend);

        Sheep sheep2 = sheep.friendClone();

        System.out.println(sheep == sheep2);
        System.out.println(sheep.getSheepFriend() == sheep2.getSheepFriend());
    }
}

运行结果
在这里插入图片描述

总结——>原型模式优缺点

优点:

  1. 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,还能够提高创建效率。
  2. 逃避构造函数的约束。
  3. 可以使用深度克隆来保存对象的状态,使用原型模式进行复制。当你需要恢复到某一时刻就直接跳到。

缺点:

  1. 需要为每一个类配备一个类克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了ocp原则。
  2. 实现深克隆时代码比较复杂。

觉得博主写的不错的读者大大们,可以点赞关注和收藏哦,谢谢各位!

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。