原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
前言
原型模式是一种创建型设计模式,它允许一个对象在创建另一个可定制的对象时,无需知道如何创建的细节。这种模式是基于克隆的概念,即通过复制一个现有对象来生成新的对象,而不是通过调用构造函数新建实例。这样,我们就可以避免与对象创建相关的成本,特别是当对象的创建过程复杂或资源消耗较大时。用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。可以去想象一下细胞分裂。
一、原型模式的核心角色
- 抽象原型(Prototype):定义了克隆自身的接口,通常会包含一个
clone
方法。 - 具体原型(Concrete Prototype):实现抽象原型的类,并实现克隆自己的逻辑。
- 客户(Client):使用原型对象的客户端,通过调用
clone
方法来创建新的对象实例。
二、具体实现
1.抽象原型
代码如下(示例):
public abstract class Prototype implements Cloneable {
public abstract void display();
public Prototype clone() {
try {
return (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // Can't happen
}
}
}
2.具体原型
代码如下(示例):
public class ConcretePrototype extends Prototype {
private String name;
public ConcretePrototype(String name) {
this.name = name;
}
@Override
public void display() {
System.out.println("Name: " + name);
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
2.客户端
代码如下(示例):
public class Client {
public static void main(String[] args) {
Prototype original = new ConcretePrototype("Original");
Prototype clone = (Prototype) original.clone();
clone.display();
}
}
在上述代码中,Cloneable
接口是 Java 中的一个标记接口(marker interface),它本身没有任何方法。当一个类实现了 Cloneable
接口时,表示该类的对象可以被克隆。在 Java 中,Object
类的 clone()
方法是受保护的(protected),因此只有实现了 Cloneable
接口的类才能调用 clone()
方法来创建对象的副本。如果一个类没有实现 Cloneable
接口,而尝试调用 clone()
方法,将会抛出 CloneNotSupportedException
异常。通过实现 Cloneable
接口,我们可以告诉编译器和运行时系统,我们的类支持克隆操作。这样,当我们调用 clone()
方法时,就不会遇到意外的异常。需要注意的是,虽然 Cloneable
接口是一个标记接口,但它并不保证 clone()
方法的行为。为了确保克隆的正确性,我们需要在具体的类中实现深拷贝的逻辑。
三、原型模式的应用场景
- 当直接创建对象的成本较高时,例如初始化需要大量资源或时间。
- 当希望避免子类化已有类的复杂性时。
- 当需要动态地创建某类对象的具体子类时,例如根据用户的输入或运行时的数据。
- 当系统需要独立于如何创建对象以及它们的表示方式时。
四、原型模式的优缺点
优点:
- 性能提升:避免了重复的初始化过程,提高了性能。
- 灵活性:可以动态地增加和减少产品的种类。
- 简化子类的创建:新的具体类可以通过复制现有的实例来创建,无需创建新的类。
缺点:
- 克隆方法的实现可能复杂:如果对象中包含多个引用类型,确保深拷贝的正确性可能会很复杂。
- 可能需要额外的管理机制:如原型管理器,来维护原型实例的缓存。
总结
原型模式提供了一种灵活且高效的对象创建方式,尤其适用于那些创建成本较高的对象。通过复制现有对象,我们可以避免复杂的初始化过程,同时保持系统的灵活性和可扩展性。然而,实现原型模式时需要注意深拷贝和浅拷贝的问题,以确保对象复制的正确性。