6月更文挑战|设计模式 —— 原型模式

574 阅读2分钟

这是我参与更文挑战的第4天,活动详情查看:更文挑战

原型模式

原型模式做为一个创建型模式,是从一个对象复制一份相同内部属性对象的模式,简单来说是克隆。一般情况下原型模式运用于创建复杂和构造耗时的实例,复制一份已存在相同实例可以让程序运行更加高效。

在Java中可以通过实现Cloneable接口,调用clone函数构造实例。事实上Cloneable是一个”标记接口“,实现Object类的Cloneable重写clone方法才具备拷贝对象的能力。

同时原型模式的拷贝还分为浅拷贝和深拷贝

浅拷贝

拷贝对象与原对象的属性完全相同,非基本类型属性仍然指向原对象属性的内存地址。

class Computer implements Cloneable{
    
    private String name;
    private CPU cpu;
    
    @Override
    public Computer clone() throws CloneNotSupportedException {
        Computer computer = (Computer) super.clone();
        computer.name = this.name;
        computer.cpu = this.cpu;
        return bubbleViewParams;
    }
}

当对Computer进行克隆时并对克隆对象进行修改,然后输出的结果如下所示。因为浅拷贝的原因,克隆对象修改基本类型属性是不影响原对象,但会影响原对象的非基本类属性。computer2修改了CPU,同时也影响computer1的CPU。

Computer computer1 = new Computer();
computer1.setNmae("computer1");
computer1.setCPU(cpu1);

Computer computer2 = computer1.clone();
computer2.setNmae("computer2");
computer2.setCPU(cpu2);

// print(computer2) -> name: computer2, cpu: cpu2
// print(computer1) -> name: computer1, cpu: cpu2

深拷贝

拷贝对象与原对象的属性完全相同,非基本类型属性也会进行克隆,不再指向原对象属性的内存地址

class Computer implements Cloneable{
    
    private String name;
    private CPU cpu;
    
    @Override
    public Computer clone() throws CloneNotSupportedException {
        Computer computer = (Computer) super.clone();
        computer.name = this.name;
        computer.cpu = (CPU)this.cpu.clone();
        return bubbleViewParams;
    }
}

再看深拷贝,对Computer进行克隆时并对克隆对象进行修改。克隆对象修改基本类型和非基本类型都不会影响原对象属性。这就是深拷贝在clone方法中对每层非基本类型属性都要做一份拷贝保证不引用原对象属性的内存地址。

Computer computer1 = new Computer();
computer1.setNmae("computer1");
computer1.setCPU(cpu1);

Computer computer2 = computer1.clone();
computer2.setNmae("computer2");
computer2.setCPU(cpu2);

// print(computer2) -> name: computer2, cpu: cpu2
// print(computer1) -> name: computer1, cpu: cpu1

总结

原型模式本质上是对象拷贝,可以理解原型模式是为了解决创建复杂对象资源消耗,在某些场景下提升创建对象的效率。其次一种运用是为了保护原对象数据,对外只提供可读操作避免对象被恶意篡改,也就是保护性拷贝,通过拷贝返回一个对象拷贝实现只读操作。

原型模式并非绝对比new方法效率更高,当对象构造方法中有特殊的初始化过程时选择clone会比new一个新对象效率更高,因为clone不会执行构造函数。所以轻量级对象可以使用new方式,负责对象采用clone。