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

news/2025/1/22 12:13:46/

原型模式 (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;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();  // 浅拷贝}@Overridepublic 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();}@Overridepublic 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;}@Overridepublic 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. 总结

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


http://www.ppmy.cn/news/1565217.html

相关文章

RestTemplate-调用远端接口应用场景

环境准备: Springboot项目 RestTemplate注入到项目中 Configurationpublic class Config {Beanpublic RestTemplate restTemplate() {return new RestTemplate(new OkHttp3ClientHttpRequestFactory());}}案例一: 使用get调用远程接口: 地址如: http://xxxx.xxx.xxx/xxx?a111&…

html与css学习笔记(2)

一、CSS引入方式 具体有 3 种引入方式&#xff0c;语法如下表格所示&#xff1a; 引入方式语法内联样式在HTML标签中使用style属性&#xff0c;例如&#xff1a;<div style"color: red;">这是一个红色的div</div>内部样式表在HTML文件的<head>标签…

Django学习笔记(安装和环境配置)-01

Django学习笔记(安装和环境配置)-01 一、创建python环境 1、可以通过安装Anaconda来创建一个python环境 # 创建一个虚拟python环境 conda create -n django python3.8 # 切换激活到创建的环境中 activate django2、安装django # 进入虚拟环境中安装django框架 pip install …

Python 常用运维模块之Shutil 模块

Python 常用运维模块之Shutil 模块 Shutil 模块复制源文件到目标路径复制源文件权限到目标文件复制源文件的最近修改时间、权限等元信息到目标文件复制源文件到目标路径&#xff08;包含文件名&#xff09;复制源文件及相关元信息到目标路径移动文件或目录获取磁盘使用情况复制…

第01章 22 使用 vtkStructuredGrid 实现一个分形的树枝状几何体

以下是一个简单的示例&#xff0c;展示如何使用 vtkStructuredGrid 实现一个分形的树枝状几何体。我们将基于递归的分形算法生成树枝结构&#xff0c;并将其存储在 vtkStructuredGrid 中。 示例代码 #include <vtkSmartPointer.h> #include <vtkPoints.h> #includ…

【C++】引用(上)

1、引用的基本使用 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型&#xff08;该数据类型要与原名的数据类型一致&#xff09; &别名原名&#xff1b; 示例&#xff1a; #include<iostream> using namespace std; int main() {int a 10;int& …

who w who

https://www.ityww.cn/733.html Linux查看用户登录信息命令-w & who & whoami Linux 基础 yvan 8年前 (2017-02-04) 3633次浏览 已收录 0个评论 显示当前已登录用户会话及动作命令-w 格式&#xff1a;w [options] [rootlocalhost ~]# w 23:46:39 up 8:29, 2 users, lo…

Linux:文件描述符fd、系统调用open

目录 一、文件基础认识 二、C语言操作文件的接口 1.> 和 >> 2.理解“当前路径” 三、相关系统调用 1.open 2.文件描述符 3.一切皆文件 4.再次理解重定向 一、文件基础认识 文件 内容 属性。换句话说&#xff0c;如果在电脑上新建了一个空白文档&#xff0…