设计模式之原型模式——浅拷贝和深拷贝

原型模式

原型模式的定义

Specify the kinds of create using prototypical ihnstance, and create new objects by copying this prototy.

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

原型模式就是通过原来的对象通过拷贝创建一个新的对象。

Java提供了一个Cloneable接口来表示一个类所产生的对象是可拷贝的,而这里的这个Cloneable只是用来标识这个类的对象是可以拷贝的,便没有其他什么作用。
众所周知Java中的所有对象都集成自Object类,这一个类中有clone()方法。

原型模式的通过代码如下:

protected native Object clone() throws CloneNotSupportedException;

这是一个native层的方法,作用是复制对象中的内容。

public class PrototypeCLass implements Cloneable {

    @Override
    protected Object clone()  {
        PrototypeCLass prototypeCLass = null;
        try {
            prototypeCLass = (PrototypeCLass) super.clone();
        } catch (CloneNotSupportedException e) {
            // 异常处理
        }
        
        return prototypeCLass;
    }
}

原型模式的优点

  • 性能优良
    原型模式是在内存中进行二进制流的拷贝,要比直接new一个对象性能好的多,特别是在循环体内产生大量的对象,原型模式能更好的体现它的优点。

  • 逃避使用构造函数的约束
    这一点既是优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点是减少了约束,但缺点也是减少了约束。

浅拷贝和深拷贝

浅拷贝

定义一个Student类,属性有id,姓名和成绩,如下:

public class Student implements Cloneable {

    private Integer id;
    private String name;
    private Map<String, Double> scores;

    public Student(Integer id, String name, Map<String, Double> scores) {
        this.id = id;
        this.name = name;
        this.scores = scores;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Map<String, Double> getScores() {
        return scores;
    }

    public void setScores(Map<String, Double> scores) {
        this.scores = scores;
    }

    @Override
    protected Student clone()  {
        Student student = null;
        try {
            student = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return student;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", scores=" + scores +
                '}';
    }
}

上面的Student类实现了Cloneable接口,重写现了Objecy类中的clone()方法。
下面写一个测试类,来测试这个类。

public class Main {
    public static void main(String[] args) {
        Map<String, Double> scores = new HashMap<>();
        scores.put("数学", 99.0);
        scores.put("英语", 99.99);

        Student student1 = new Student(1, "张三", scores);
        Student student2 = student1.clone();

        student2.setId(2);
        student2.setName("李四");
        student2.getScores().put("语文", 100.0);

        System.out.println(student1);
        System.out.println(student2);
    }
}

输入:

Student{id=1, name='张三', scores={数学=99.0, 语文=100.0, 英语=99.99}}
Student{id=2, name='李四', scores={数学=99.0, 语文=100.0, 英语=99.99}}

what student2中修改的在student1中也起作用了。

这是因为使用Object中的clone()方法拷贝对象的时候,对于对象内部的数组、引用对象等都不拷贝,还是指向被拷贝对象中引用所在的地址,这种拷贝叫做浅拷贝。

深拷贝

所谓的深拷贝就是对于那些只是拷贝引用而不拷贝对象的属性进行单独拷贝。比如Student类中的score属性是Map类型的,而Map类型是一个对象,在浅拷贝的时候只拷贝了应用,所以在这里应该白score也复制了,如下:

@Override
protected Student clone()  {
    Student student = null;
    try {
        student = (Student) super.clone();
        student.scores = (Map<String, Double>) ((HashMap)this.scores).clone();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    return student;
}

这里值得注意的一点是被final修饰变量不能被克隆。

参考

《设计模式之禅》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值