Java设计模式 六 原型模式 (Prototype Pattern)

原型模式 (Prototype Pattern)

原型模式是一种创建型设计模式 ,通过复制现有对象来创建新对象,而不是直接实例化类。这种模式适用于创建成本较高的对象,或者需要重复创建相似对象的场景。

原型模式的核心思想是:

通过对象自身提供的复制方法(通常是 clone() 方法),快速生成新对象,同时保持高效和灵活。


1. 原型模式的组成

  • Prototype(原型接口): 定义一个用于复制自身的接口,通常包括 clone() 方法。
  • ConcretePrototype(具体原型类): 实现 Prototype 接口,定义具体的克隆方法。
  • Client(客户端): 通过调用原型对象的 clone() 方法创建新的对象,而不需要知道具体类的信息。

2. 原型模式的优点

  • 提高对象创建效率: 克隆比使用构造函数重新实例化对象要高效。
  • 减少耦合: 客户端不需要依赖具体类,通过原型接口即可创建对象。
  • 动态创建对象: 可以在运行时动态调整对象的状态并克隆,灵活性强。

3. 原型模式的缺点

  • 复杂性增加: 如果对象包含复杂的引用类型,可能需要处理深拷贝和浅拷贝的问题。
  • 依赖 clone() 方法: 在 Java 中,必须正确实现 clone() 方法,且需要实现 Cloneable 接口,这可能会破坏类的封装性。

4. Java 中的实现

1) 实现浅拷贝的原型模式

浅拷贝只复制对象本身及其基本类型的字段,引用类型字段仅复制引用地址。

示例代码:

java 复制代码
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();  // 浅拷贝
    }

    @Override
    public String toString() {
        return "Prototype [field=" + field + "]";
    }
}

public class Client {
    public static void main(String[] args) {
        try {
            // 创建原型对象
            Prototype prototype = new Prototype("Original");
            System.out.println("Original: " + prototype);

            // 克隆对象
            Prototype clonedPrototype = (Prototype) prototype.clone();
            System.out.println("Cloned: " + clonedPrototype);

            // 修改克隆对象的字段值
            clonedPrototype.setField("Cloned");
            System.out.println("After Modification:");
            System.out.println("Original: " + prototype);
            System.out.println("Cloned: " + clonedPrototype);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

输出:

复制代码
Original: Prototype [field=Original]
Cloned: Prototype [field=Original]
After Modification:
Original: Prototype [field=Original]
Cloned: Prototype [field=Cloned]

2) 实现深拷贝的原型模式

深拷贝不仅复制对象本身,还递归复制引用类型的字段。

示例代码:

java 复制代码
import java.io.*;

class DeepPrototype implements Serializable {
    private static final long serialVersionUID = 1L;
    private String field;
    private Reference reference;

    public DeepPrototype(String field, Reference reference) {
        this.field = field;
        this.reference = reference;
    }

    public String getField() {
        return field;
    }

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

    public Reference getReference() {
        return reference;
    }

    public void setReference(Reference reference) {
        this.reference = reference;
    }

    // 深拷贝方法
    public DeepPrototype deepClone() throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (DeepPrototype) ois.readObject();
    }

    @Override
    public String toString() {
        return "DeepPrototype [field=" + field + ", reference=" + reference + "]";
    }
}

class Reference implements Serializable {
    private static final long serialVersionUID = 1L;
    private String data;

    public Reference(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Reference [data=" + data + "]";
    }
}

public class Client {
    public static void main(String[] args) {
        try {
            // 创建原型对象
            Reference reference = new Reference("Original Reference");
            DeepPrototype prototype = new DeepPrototype("Original Field", reference);
            System.out.println("Original: " + prototype);

            // 深拷贝
            DeepPrototype clonedPrototype = prototype.deepClone();
            System.out.println("Cloned: " + clonedPrototype);

            // 修改克隆对象的引用字段值
            clonedPrototype.getReference().setData("Modified Reference");
            System.out.println("After Modification:");
            System.out.println("Original: " + prototype);
            System.out.println("Cloned: " + clonedPrototype);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

输出:

复制代码
Original: DeepPrototype [field=Original Field, reference=Reference [data=Original Reference]]
Cloned: DeepPrototype [field=Original Field, reference=Reference [data=Original Reference]]
After Modification:
Original: DeepPrototype [field=Original Field, reference=Reference [data=Original Reference]]
Cloned: DeepPrototype [field=Original Field, reference=Reference [data=Modified Reference]]

5. 原型模式的应用场景

  • 对象创建成本较高时: 如对象初始化过程复杂,或需要大量计算。
  • 对象差异很小且需要频繁创建时: 使用克隆可以减少重复代码。
  • 需要保存对象历史状态时: 通过克隆保存对象的副本以实现备份或撤销功能。
  • 需要创建与已有对象相似的对象时: 克隆提供了一种快速复制现有对象的方法。

6. 优缺点总结

优点:
  • 性能优越: 通过克隆直接复制对象,而不需要重新构建。
  • 简化创建过程: 尤其是对于包含大量字段的对象。
  • 动态创建: 可以在运行时动态创建对象,而无需依赖类。
缺点:
  • 复杂性: 需要正确实现 clone() 方法,尤其是处理复杂对象中的深拷贝。
  • 依赖 Cloneable 接口: Java 中的 clone() 方法存在局限性,并且可能破坏封装性。
  • 潜在安全隐患: 如果对象中的字段不安全或未正确处理,可能导致意外行为。

7. 与其他模式的比较

模式 主要用途 与原型模式的区别
工厂方法模式 通过子类决定对象创建 原型模式通过克隆现有对象来创建
抽象工厂模式 创建相关或依赖对象的产品族 原型模式关注单个对象的复制
建造者模式 分步骤构建复杂对象 原型模式直接克隆对象,无需分步骤构建

8. 总结

原型模式是解决对象重复创建问题的强大工具,特别适合那些创建成本高或需要快速生成对象的场景。根据具体需求,可以选择浅拷贝或深拷贝的实现方式。尽管实现上可能会稍复杂,但它提供了灵活性和高效性,是值得掌握的重要设计模式之一。

相关推荐
SL_staff23 分钟前
从RBAC到场景化授权:《无忧·企业文档》三级权限模型的技术实践解析
java·开源·产品
传奇开心果编程1 小时前
【springboot基础语法学与练】第 1 课:从零开始
java·spring boot·后端·学习
SL_staff1 小时前
财务系统慎用低代码?从数据模型闭环看合规落地的技术实践
java·低代码·全栈
滕州市燕猫虎计算机科技工作室个体工商户1 小时前
IDEA:Command line is too long
java·ide·intellij-idea
步行cgn2 小时前
Spring p 命名空间注入详解
java·前端·spring
YatHinLay2 小时前
MyBatis 流式查询实战:ResultHandler 处理海量数据
java
天天被压力2 小时前
【跨市场数据实战 #08】可转债折价机会怎么筛:3个接口抓比价、列表和实时盘口
java·人工智能·python
张某布响丸辣3 小时前
附件下载的安全边界:路径白名单、NAS 哨兵文件与 Redis Lua 一次性令牌
java·redis·redis lua·nas哨兵
YatHinLay4 小时前
Spring Boot + Calcite 实现跨库查询
java
酷炫码神4 小时前
MosMos 创意效果与能力边界展示
java