Java原型模式源码剖析及使用场景

时间:2024-03-09 14:24:24

一、 项目案例

在项目开发中,我们可以在需要创建复杂对象或者需要大量创建对象的场景下使用原型模式。比如,我们需要在内存中缓存大量的图像对象,每个图像对象都包含了一些元数据信息。如果每次都从头创建一个新的图像对象,势必会消耗大量的系统资源。

这时,我们可以使用原型模式来解决这个问题。首先,我们创建一个原型图像对象,并初始化它的元数据信息。然后,每当我们需要创建一个新的图像对象时,只需要从原型对象上克隆一个副本出来,就可以避免重复创建对象的开销。

// 图像对象
public class Image implements Cloneable {
    private String name;
    private byte[] data;
    private int width;
    private int height;

    // 构造函数和getter/setter方法...

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

// 原型管理器
public class PrototypeManager {
    private static Map<String, Image> prototypes = new HashMap<>();

    public static void addPrototype(String name, Image image) {
        prototypes.put(name, image);
    }

    public static Image getPrototype(String name) throws CloneNotSupportedException {
        return (Image) prototypes.get(name).clone();
    }
}

在上面的示例中,我们定义了一个Image类,实现了Cloneable接口,允许对象被克隆。PrototypeManager类充当了原型管理器的角色,它维护了一个原型对象的映射表,通过addPrototype()方法可以添加新的原型对象,通过getPrototype()方法可以获取一个原型对象的克隆副本。

二、Java源码案例

在Java标准库中,Object类提供了clone()方法,允许对象克隆自身。这就是原型模式在Java中的一个体现。不过,由于Object类的clone()方法是一个受保护的方法,所以如果要使用这个方法,必须在自定义的类中重写它。

public class MyClass implements Cloneable {
    // 其他属性和方法...

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

在上面的示例中,MyClass实现了Cloneable接口,并重写了clone()方法。当调用myObject.clone()时,就会创建一个myObject的克隆副本。

需要注意的是,Object类的clone()方法执行的是浅拷贝,如果对象中包含其他对象的引用,那么这些引用指向的对象并不会被克隆。如果需要执行深拷贝,就需要在自定义的clone()方法中手动实现对引用对象的克隆。

三、原型模式分浅拷贝和深拷贝
Java 中的原型模式提供了一种创建对象的简单方式,通过将一个对象复制出一个新的实例来创建新对象。在复制对象时,Java 提供了两种不同的方式:浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。

1.浅拷贝(Shallow Copy)

浅拷贝是指创建一个新对象,然后将当前对象的非静态字段值复制到该新对象中。但是,如果字段是引用类型,则会将引用地址复制给新对象,因此新对象和原对象引用同一个对象。换句话说,新对象和原对象仍然共享部分内存空间。

public class Employee implements Cloneable {
    private int id;
    private String name;
    private Department department; // 引用类型

    // 浅拷贝实现
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    // 构造函数、getter、setter
    // ...
}

public class Department {
    private String name;
    // ...
}

在上面的示例中,如果我们对 Employee 对象进行浅拷贝,则新对象的 department 字段将引用与原对象相同的 Department 对象。因此,如果修改了新对象的 department 字段,原对象的 department 字段也会受到影响。

2.深拷贝(Deep Copy)

深拷贝是指创建一个新对象,并且递归复制当前对象所引用的对象。也就是说,对于所有的引用类型字段,都将创建一个新的对象并复制其中的内容。这样,新对象和原对象之间就完全分离开来,互不影响。

public class Employee implements Cloneable {
    private int id;
    private String name;
    private Department department; // 引用类型

    // 深拷贝实现
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Employee clone = (Employee) super.clone();
        clone.department = (Department) department.clone(); // 对引用类型字段进行深拷贝
        return clone;
    }

    // 构造函数、getter、setter
    // ...
}

public class Department implements Cloneable {
    private String name;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    // 构造函数、getter、setter
    // ...
}

在上面的示例中,我们实现了 Employee 类的深拷贝。当克隆一个 Employee 对象时,不仅会复制基本类型字段,还会递归复制引用类型字段 department。因此,新对象和原对象的 department 字段指向不同的对象,修改新对象的 department 字段不会影响到原对象。需要注意的是,深拷贝通常会比浅拷贝更加复杂和耗时,因为需要递归复制所有引用类型的对象。

原型模式通过对象克隆的方式来创建新的对象,避免了重复创建对象的开销,提高了系统的性能和效率。在实际项目中,我们可以根据具体情况选择是否使用原型模式,特别是在需要创建大量复杂对象的场景下,原型模式会非常有用。