当前位置: 首页 > news >正文

原型设计模式

原型模式(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制(克隆)现有对象来创建新对象,而无需显式地使用构造函数创建新对象。这种模式通常用于创建成本较高或复杂的对象,以避免重复的初始化工作。

结构

  1. 原型接口(Prototype Interface):通常需要创建一个原型接口,该接口定义了一个clone方法,用于复制对象。所有需要支持克隆操作的类都需要实现这个接口。
  2. 具体原型(Concrete Prototype):具体原型类是实现了原型接口的类,它实际上进行对象的复制操作。具体原型类需要实现clone方法来克隆自身。
  3. 客户端(Client):客户端代码通过原型接口来请求克隆操作(即使用具体原型类中的clone()方法来复制新对象),而不需要知道具体的对象创建细节。

实现

原型模式可以分为浅克隆深克隆两种形式,取决于复制的方式。

  • 浅克隆:创建一个新对象,新对象的属性与原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有的对象地址。

Java中的Object类中提供了clone()方法来实现浅克隆。

class Prototype implements Cloneable{public Prototype() {System.out.println("创建具体的原型对象");}@Overrideprotected Prototype  clone() throws CloneNotSupportedException {System.out.println("复制成功!");return (Prototype) super.clone();}
}public class PrototypeDemo {public static void main(String[] args) throws CloneNotSupportedException{Prototype original = new Prototype();Prototype clone = original.clone();System.out.println(original == clone); //false}
}

上面的方法很简单,当然,还有另外一种方法,就是自己创建原型接口,按照上面的原型模式的结构来实现

// 原型接口
interface Prototype {Prototype clone();
}// 具体原型类
class ConcretePrototype implements Prototype {private String data;public ConcretePrototype(String data) {this.data = data;}@Overridepublic Prototype clone() {return new ConcretePrototype(this.data);}public String getData() {return data;}
}public class PrototypeDemo {public static void main(String[] args) {// 创建一个具体原型对象Prototype original = new ConcretePrototype("Hello, world!");// 克隆原型对象来创建新对象Prototype clone = original.clone();// 输出原型和克隆对象的数据System.out.println("Original Data: " + ((ConcretePrototype) original).getData());System.out.println("Clone Data: " + ((ConcretePrototype) clone).getData());}
}

使用场景

原型模式使用场景有:

  1. 对象的创建成本较高:如果创建一个对象的成本很高,例如需要从数据库中加载大量数据或进行复杂的计算,那么使用原型模式可以避免多次创建相同的对象,而是通过克隆已有对象来创建新对象,从而提高性能。

  2. 对象的创建过程复杂:当对象的创建过程非常复杂,包括多个步骤或依赖于其他对象时,使用原型模式可以简化代码,因为您只需克隆一个已有对象,而不必重复执行复杂的创建步骤。

  3. 需要保持对象的不变性:有些对象需要保持不变性,即不能通过直接赋值属性的方式修改其状态。原型模式可以帮助您创建对象的副本,而不会影响原始对象的状态。

  4. 大量相似对象的创建:当需要创建大量相似但略有差异的对象时,原型模式非常有用。您可以创建一个原型对象,然后根据需要克隆该对象并进行适当的修改。

  5. 支持动态配置对象:原型模式允许您在运行时动态配置对象,通过克隆已有对象并进行修改,而不必硬编码不同的配置选项。

  6. 减少子类的创建:在某些情况下,如果您有多个子类,而这些子类只有一些差异,可以使用原型模式来创建这些子类的实例,而不必为每个子类都创建一个独立的类。

深克隆

在实现深克隆时,有几种常见的方式:

  1. 手动实现深克隆:这是最基本的方式,开发人员需要手动编写代码来遍历原始对象的属性和子对象,并创建相应的新对象来存储复制后的数据。这通常涉及递归操作,以确保所有嵌套对象也被深克隆。
class Address implements Cloneable {private String street;private String city;public String getStreet() {return street;}public void setStreet(String street) {this.street = street;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public Address(String street, String city) {this.street = street;this.city = city;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}class Person implements Cloneable {public String getName() {return name;}public void setName(String name) {this.name = name;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}public Person(String name, Address address) {this.name = name;this.address = address;}private String name;private Address address;@Overrideprotected Object clone() throws CloneNotSupportedException {Person clonedPerson = (Person) super.clone();clonedPerson.address = (Address) address.clone();return clonedPerson;}
}public class Main {public static void main(String[] args) throws CloneNotSupportedException {Address address = new Address("步行街", "北京");Person originalPerson = new Person("Alice", address);Person clonedPerson = (Person) originalPerson.clone();System.out.println(originalPerson.getName()+"   "+originalPerson.getAddress().getStreet()); // Alice   步行街clonedPerson.setName("Bob");clonedPerson.getAddress().setStreet("人民公园");System.out.println(clonedPerson.getName()+"   "+clonedPerson.getAddress().getStreet());   // Bob   人民公园}
}
  1. 使用序列化和反序列化:这种方式需要将原始对象序列化为一个字节流,然后再将其反序列化为新对象。这可以通过语言内置的序列化机制或第三方库来实现。在这个过程中,对象的所有属性和嵌套对象都会被复制。
import java.io.*;class Address implements Serializable {private String street;private String city;public String getStreet() {return street;}public void setStreet(String street) {this.street = street;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public Address(String street, String city) {this.street = street;this.city = city;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}class Person implements Serializable  {public String getName() {return name;}public void setName(String name) {this.name = name;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}public Person(String name, Address address) {this.name = name;this.address = address;}private String name;private Address address;@Overrideprotected Object clone() throws CloneNotSupportedException {Person clonedPerson = (Person) super.clone();clonedPerson.address = (Address) address.clone();return clonedPerson;}
}public class Main {public static void main(String[] args) throws IOException, ClassNotFoundException {Address address = new Address("步行街", "北京");Person originalPerson = new Person("Alice", address);// 序列化主类ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(originalPerson);// 反序列化创造克隆类ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);Person clonedPerson = (Person) ois.readObject();System.out.println(originalPerson.getName()+"   "+originalPerson.getAddress().getStreet()); // Alice   步行街clonedPerson.setName("Bob");clonedPerson.getAddress().setStreet("人民公园");System.out.println(clonedPerson.getName()+"   "+clonedPerson.getAddress().getStreet());   // Bob   人民公园}
}

相关文章:

  • 工作心得——css让元素居中的方法
  • 嵌入式linux驱动开发篇之设备树
  • php 数组函数
  • 关于jupyter的一些小笔记
  • Linux第48步_编译正点原子的出厂Linux内核源码
  • 【精选】Java面向对象进阶——接口细节:成员特点和接口的各种关系
  • 随想录刷题笔记 —二叉树篇7 617合并二叉树 700二叉搜索树中的搜索 98验证二叉搜索树
  • C++数据结构与算法——双指针法
  • python-使用ffmpeg批量修改文件的后缀名
  • vue自定义指令(图文示例)
  • Leetcode3026. 最大好子数组和
  • 基于BP算法的SAR成像matlab仿真
  • Sora时代,我们的AI应该何去何从?——关于Sora大模型的思考
  • IIC--集成电路总线
  • C++ 多起点的bfs(五十九)【第六篇】
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • HTTP中的ETag在移动客户端的应用
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • java正则表式的使用
  • JDK 6和JDK 7中的substring()方法
  • js算法-归并排序(merge_sort)
  • k8s如何管理Pod
  • Laravel 实践之路: 数据库迁移与数据填充
  • node和express搭建代理服务器(源码)
  • spring + angular 实现导出excel
  • Spring Boot快速入门(一):Hello Spring Boot
  • 前端js -- this指向总结。
  • 使用parted解决大于2T的磁盘分区
  • 突破自己的技术思维
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 最近的计划
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • #微信小程序(布局、渲染层基础知识)
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (7)STL算法之交换赋值
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (poj1.2.1)1970(筛选法模拟)
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .net CHARTING图表控件下载地址
  • .NET Core中Emit的使用
  • .Net 代码性能 - (1)
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .net 无限分类
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET和.COM和.CN域名区别
  • .NET基础篇——反射的奥妙
  • .net中调用windows performance记录性能信息
  • @configuration注解_2w字长文给你讲透了配置类为什么要添加 @Configuration注解
  • [ 英语 ] 马斯克抱水槽“入主”推特总部中那句 Let that sink in 到底是什么梗?
  • [2544]最短路 (两种算法)(HDU)