java设计模式:02-02-原型模式

时间:2024-07-20 11:13:39

原型模式(Prototype Pattern)

原型模式(Prototype Pattern)用于创建重复的对象,同时又能保证性能。它属于创建型设计模式,使用现有的实例来创建新对象,而不是每次都通过实例化来创建新对象。原型模式通过克隆已有对象来创建新的实例。

原型模式的应用场景

  • 对象初始化消耗大量资源:如需要加载大量数据或建立复杂的网络连接。
  • 创建新对象的代价昂贵:如涉及到复杂的计算或繁琐的配置。
  • 系统需要大量类似对象:如需要创建大量类似的文档、图形或对象。
  • 避免类层次结构的复杂性:如避免使用构造器或工厂模式的复杂创建逻辑。

原型模式的实现方式

1. 使用 Cloneable 接口实现浅拷贝

思想:实现 Cloneable 接口,并重写 clone 方法,通过浅拷贝来创建对象的副本。浅拷贝只复制对象的基本类型字段和引用类型字段的引用,而不复制引用类型字段指向的对象。

实现方式

class Prototype implements Cloneable {
    private String field;

    public Prototype(String field) {
        this.field = field;
    }

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

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

public class PrototypePattern {
    public static void main(String[] args) {
        try {
            Prototype original = new Prototype("Original");
            Prototype clone = (Prototype) original.clone();

            System.out.println("Original: " + original.getField());
            System.out.println("Clone: " + clone.getField());

            clone.setField("Clone");
            System.out.println("Original after modifying clone: " + original.getField());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

优点

  • 实现简单,直接使用 Java 提供的 Cloneable 接口。

缺点

  • 浅拷贝仅复制基本类型字段和引用类型字段的引用,不复制引用类型字段指向的对象,可能导致共享引用问题。
2. 实现深拷贝

思想:通过序列化和反序列化,或手动复制引用类型字段,来实现对象的深拷贝。深拷贝不仅复制对象的基本类型字段,还复制引用类型字段指向的对象。

实现方式

  1. 使用序列化实现深拷贝
import java.io.*;

class PrototypeDeep implements Serializable {
    private static final long serialVersionUID = 1L;
    private String field;

    public PrototypeDeep(String field) {
        this.field = field;
    }

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public PrototypeDeep deepClone() {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (PrototypeDeep) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

public class PrototypePatternDeepCopy {
    public static void main(String[] args) {
        PrototypeDeep original = new PrototypeDeep("Original");
        PrototypeDeep clone = original.deepClone();

        System.out.println("Original: " + original.getField());
        System.out.println("Clone: " + clone.getField());

        clone.setField("Clone");
        System.out.println("Original after modifying clone: " + original.getField());
    }
}

优点

  • 深拷贝可以完全独立地复制对象,包括其引用类型字段所指向的对象,避免共享引用问题。

缺点

  • 序列化和反序列化开销较大。
  • 需要确保所有引用类型字段实现 Serializable 接口。
  1. 手动实现深拷贝
class InnerObject implements Cloneable {
    private String innerField;

    public InnerObject(String innerField) {
        this.innerField = innerField;
    }

    public String getInnerField() {
        return innerField;
    }

    public void setInnerField(String innerField) {
        this.innerField = innerField;
    }

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

class PrototypeManualDeep implements Cloneable {
    private String field;
    private InnerObject innerObject;

    public PrototypeManualDeep(String field, InnerObject innerObject) {
        this.field = field;
        this.innerObject = innerObject;
    }

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public InnerObject getInnerObject() {
        return innerObject;
    }

    public void setInnerObject(InnerObject innerObject) {
        this.innerObject = innerObject;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        PrototypeManualDeep clone = (PrototypeManualDeep) super.clone();
        clone.innerObject = (InnerObject) innerObject.clone();
        return clone;
    }
}

public class PrototypePatternManualDeepCopy {
    public static void main(String[] args) {
        InnerObject innerObject = new InnerObject("InnerOriginal");
        PrototypeManualDeep original = new PrototypeManualDeep("Original", innerObject);
        PrototypeManualDeep clone;

        try {
            clone = (PrototypeManualDeep) original.clone();
            System.out.println("Original: " + original.getField() + ", Inner: " + original.getInnerObject().getInnerField());
            System.out.println("Clone: " + clone.getField() + ", Inner: " + clone.getInnerObject().getInnerField());

            clone.setField("Clone");
            clone.getInnerObject().setInnerField("InnerClone");

            System.out.println("Original after modifying clone: " + original.getField() + ", Inner: " + original.getInnerObject().getInnerField());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

优点

  • 通过手动实现深拷贝,可以精确控制拷贝的过程。

缺点

  • 手动实现深拷贝代码复杂,容易出错。
  • 需要为每个引用类型字段单独实现拷贝逻辑。

总结

实现方式 优点 缺点
浅拷贝 实现简单,直接使用 Cloneable 接口 仅复制基本类型字段和引用类型字段的引用,可能导致共享引用问题
深拷贝(序列化实现) 完全独立地复制对象,包括引用类型字段所指向的对象,避免共享引用问题 序列化和反序列化开销较大,需要确保所有引用类型字段实现 Serializable 接口
深拷贝(手动实现) 精确控制拷贝过程 代码复杂,容易出错,需要为每个引用类型字段单独实现拷贝逻辑

选择哪种实现方式应根据具体的应用场景和需求来决定。如果对象较为简单且不涉及复杂的引用类型字段,可以使用浅拷贝。如果对象复杂且需要完全独立的副本,可以选择序列化实现深拷贝或手动实现深拷贝。