重读 Java 设计模式: 深入探讨原型模式,灵活复制对象

news2024/11/23 16:45:15

引言

在软件开发中,经常会遇到需要创建对象的情况。有时候,我们希望创建一个新的对象,但又不想通过传统的构造方法来创建,而是希望通过复制一个现有对象的方式来创建新的对象。这时,原型模式就能派上用场了。原型模式是一种创建型设计模式,它通过复制现有对象来创建新对象,从而提高了代码的效率和可维护性。

本篇文章将深入探讨原型模式的原理、应用场景以及在实际项目中的使用方法。

一、理解原型模式

原型模式属于创建型设计模式,其核心思想是通过复制现有对象来创建新的对象,而不是通过传统的构造方法。在原型模式中,原型对象是被复制的对象,而新对象是根据原型对象创建的副本。这种方式既避免了直接使用构造方法创建对象的繁琐过程,又可以保证新对象的属性与原型对象一致。

二、原型模式的应用场景

原型模式适用于以下几种场景:

  1. 对象的创建过程比较复杂,但又希望保持对象的属性一致。
  2. 需要避免使用复杂的构造方法来创建对象。
  3. 需要动态地生成对象,而不是静态地使用类的构造方法。

在实际项目中,原型模式通常用于以下几种情况:

  • 在大量对象需要创建,且创建过程相对复杂时,使用原型模式可以提高代码效率。
  • 当需要创建的对象属性与现有对象相似或相同,但需要稍作修改时,可以通过复制原型对象并修改部分属性来创建新对象。

三、原型模式的实现方式

原型模式的实现方式主要有两种:浅拷贝和深拷贝。

  1. 浅拷贝:浅拷贝是指复制对象时,只复制对象本身及其基本数据类型的属性,而不会复制对象所引用的其他对象。即使原型对象中包含了引用类型的属性,复制后的新对象与原对象仍会共享同一个引用类型的属性。
  2. 深拷贝:深拷贝是指复制对象时,不仅复制对象本身及其基本数据类型的属性,还会递归复制对象所引用的其他对象。这样,即使原型对象中包含了引用类型的属性,复制后的新对象与原对象不会共享同一个引用类型的属性。

在实现原型模式时,需要根据具体的需求选择合适的拷贝方式,以确保复制出的新对象能够满足业务需求。

四、原型模式的代码示例

先来看下相关 UML 图:

image-20240331094021388

下面通过一个简单的示例来演示原型模式的代码实现:

package com.markus.desgin.mode.creational.prototype;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public abstract class Car implements Cloneable {

  private String carName;
  private String carType;

  abstract void drive();

  public String getCarName() {
    return carName;
  }

  public void setCarName(String carName) {
    this.carName = carName;
  }

  public String getCarType() {
    return carType;
  }

  public void setCarType(String carType) {
    this.carType = carType;
  }

  @Override
  public Object clone() {
    try {
      return super.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
    return null;
  }
}
package com.markus.desgin.mode.creational.prototype;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public class XiaoMiSuvCar extends Car {
  @Override
  void drive() {
    String message = "carName: " + this.getCarName() + ", carType: " + this.getCarType();
    System.out.println(message + " 已启动");
  }
}

package com.markus.desgin.mode.creational.prototype;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public class BydSuvCar extends Car {
  @Override
  void drive() {
    String message = "carName: " + this.getCarName() + ", carType: " + this.getCarType();
    System.out.println(message + " 已启动");
  }
}

package com.markus.desgin.mode.creational.prototype;

import java.util.HashMap;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public class CarCache {
  private static HashMap<String, Car> carMap = new HashMap<String, Car>();

  static {
    XiaoMiSuvCar xiaoMiSuvCar = new XiaoMiSuvCar();
    xiaoMiSuvCar.setCarType("SUV");
    xiaoMiSuvCar.setCarName("XiaoMi");
    carMap.put("Xiaomi", xiaoMiSuvCar);

    BydSuvCar bydSuvCar = new BydSuvCar();
    bydSuvCar.setCarType("SUV");
    bydSuvCar.setCarName("BYD");
    carMap.put("BYD", bydSuvCar);
  }

  public static Car getCar(String key) {
    Car car = carMap.get(key);
    return (Car) car.clone();
  }
}
package com.markus.desgin.mode.creational.prototype;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public class PrototypePatternDemo {
  public static void main(String[] args) {
    Car car = CarCache.getCar("Xiaomi");
    car.drive();

    car = CarCache.getCar("BYD");
    car.drive();

    Car car2 = CarCache.getCar("BYD");
    System.out.println("car == car2 : " + (car == car2));
  }
}

在上面的示例中,我们通过实现Cloneable接口并重写clone()方法,实现了原型对象的浅拷贝。

五、原型模式在 Spring 的应用

我们知道在 Spring 框架中 Bean 的作用域除了单例模式,还有原型模式。

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {

	/**
	 * Scope identifier for the standard singleton scope: {@value}.
	 * <p>Custom scopes can be added via {@code registerScope}.
	 * @see #registerScope
	 */
	String SCOPE_SINGLETON = "singleton";

	/**
	 * Scope identifier for the standard prototype scope: {@value}.
	 * <p>Custom scopes can be added via {@code registerScope}.
	 * @see #registerScope
	 */
	String SCOPE_PROTOTYPE = "prototype";
}

在 Spring 框架中,原型模式和我们本篇说的原型模式实现有所不同。Spring 中创建 Bean 实例是通过反射重复创建。

image-20240331095234349

六、设计模式百宝箱

在本节,我们继续填充我们的百宝箱:

  • 面向对象基础
    • 抽象
    • 封装
    • 多态
    • 继承
  • 面向对象原则
    • 依赖抽象,不要依赖具体类
    • 针对接口编程,不针对具体实现编程
    • 类应该对扩展开放,对修改关闭
    • 为交互对象之间的松耦合设计而努力
  • 面向对象设计模式
    • 简单工厂模式:定义了一个创建对象的接口,将创建对象的内容从客户端抽离出来
    • 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类
    • 原型模式:通过复制现有对象来创建新对象,提高代码效率和可维护性

七、总结

通过本文的学习,我们了解了原型模式的原理、应用场景以及实现方式。原型模式通过复制现有对象来创建新对象,可以提高代码的效率和可维护性,适用于对象创建过程比较复杂、需要保持对象属性一致或动态生成对象的情况。在实现原型模式时,需要注意选择合适的拷贝方式,以确保复制出的新对象能够满足业务需求。

希望本文对你理解和应用原型模式有所帮助,欢迎继续关注我们后续的设计模式深入探讨系列文章。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1559788.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【51单片机入门记录】A2普中开发板实验课例程

一、开发板原理图 二、例程 &#xff08;1&#xff09;呼吸灯 #include <STC89C5xRC.H> #include<intrins.h>unsigned int PWM_wanttime0; //想要多长时间改变的占空比一次 unsigned int Breath_wanttime0; //想要多长时间改变呼气或者吸气的值时间 unsigned …

Android Studio 新建aar包

有几个注意事项 第一是注意是选择Android library这个包注意moudle name不能包含apk这三个字符

动手学机器学习双线性模型+习题

在数学中&#xff0c;双线性的含义为&#xff0c;二元函数固定任意一个自变量时&#xff0c;函数关于另一个自变量线性 矩阵分解 设想有N个用户和M部电影&#xff0c;构建一个用户画像库&#xff0c;包含每个用户更偏好哪些类型的特征&#xff0c;以及偏好的程度。假设特征的个…

0.5米多光谱卫星影像在农业中进行地物非粮化、非农化监测

一、引言 随着科技的发展&#xff0c;卫星遥感技术已经成为了农业领域中重要的数据来源。其中&#xff0c;多光谱卫星影像以其独特的优势&#xff0c;在农业应用中发挥着越来越重要的作用。本文将重点探讨0.5米加2米多光谱卫星影像在农业中的应用。 二、多光谱卫星影像概述 多…

ESP8266 WiFi物联网智能插座—上位机软件实现

1、软件架构 上位机主要作为下位机数据上传服务端以及节点调试的控制端&#xff0c;可以等效认为是专属版本调试工具。针对智能插座协议&#xff0c;对于下位机进行可视化监测和管理。 软件技术架构如下&#xff0c;主要为针对 Windows 的PC 端应用程序&#xff0c;采用WPF以及…

Mock.js的基本使用

mock顾名思义&#xff0c;就是模拟的意思&#xff0c;它模拟什么呢&#xff1f;假设我们在开发的过程中&#xff0c;我们需要使用到接口&#xff0c;但是后端接口并没有完善&#xff0c;那么我们就可以使用到mock.js&#xff0c;它可以随机生成数据&#xff0c;拦截AJAX请求&am…

壁纸小程序Vue3(分类页面和用户页面基础布局)

1.配置tabBar pages.json "tabBar": {"color": "#9799a5","selectedColor": "#28B389","list": [{"text": "推荐","pagePath": "pages/index/index","iconPath&quo…

网络安全-内网渗透2

一、MIC 将我们上次未描述完的MIC在这里详细解释一下 咱们所抓的第二个包会给返回一个服务端的challenge 之后服务器回包的第三个包会回复一个client challenge 所以咱们客户端和服务端现在分别有两个challenge&#xff0c;相当于客户端和服务端互相交换了一下challenge 因此…

《深度学习入门之PyTorch》书籍阅读笔记

《深度学习入门之PyTorch》书籍阅读笔记 ISBN 978-7-121-32620-2 多层全连接神经网络 Pytorch基础 Tensor张量 是一个多维矩阵&#xff0c;pytorch的tensor可以和numpy的ndarray相互转换&#xff0c;但numpy的ndarray只能在CPU上运行。不同数据类型的Tensor&#xff0c;t…

nginx的https与动态负载均衡

nginx的https 证书可以根据你的域名和服务器服务商去进行签发 , 比如 : 阿里云 腾讯云 百度云 华为云等 这里使用的是腾讯云 : 下载证书 : 选择 nginx: 下载之后传递到服务器上。 下面开始配置nginx的https: 1. 解压下载的证书包 cd /etc/ssl unzip xxcc.dwa_nginx.zip mv…

JMeter基础用法和测试WebSocket请求

目录 JMeter websocket插件安装测试接口的编写添加测试线程组创建取样器创建WebSocket连接创建循环控制器创建WebSocket request-response Sampler创建固定定时器 正则匹配上一个请求的数据做为当前请求参数正则编写使用匹配值 CSV文件读取参数添加汇总报告和结果树 JMeter web…

zookeeper如何管理客户端与服务端之间的链接?(zookeeper sessions)

zookeeper客户端与服务端之间的链接用zookeeper session表示。 zookeeper session有三个状态&#xff1a; CONNECTING, ASSOCIATING, CONNECTED, CONNECTEDREADONLY, CLOSED, AUTH_FAILED, NOT_CONNECTED&#xff08;start时的状态&#xff09; 1、CONNECTING 。 表明客户…

vulhub中Apache Solr 远程命令执行漏洞复现(CVE-2017-12629)

Apache Solr 是一个开源的搜索服务器。Solr 使用 Java 语言开发&#xff0c;主要基于 HTTP 和 Apache Lucene 实现。原理大致是文档通过Http利用XML加到一个搜索集合中。查询该集合也是通过 http收到一个XML/JSON响应来实现。此次7.1.0之前版本总共爆出两个漏洞&#xff1a;[XM…

金三银四面试题(九):JVM常见面试题(3)

今天我们继续探讨常见的JVM面试题。这些问题不比之前的问题庞大&#xff0c;多用于面试中JVM部分的热身运动&#xff0c;开胃菜&#xff0c;但是大家已经要认真准备。 你能保证GC 执行吗&#xff1f; 不能&#xff0c;虽然你可以调用System.gc() 或者Runtime.gc()&#xff0c…

vue3+threejs新手从零开发卡牌游戏(二十四):添加p2战斗逻辑

用代码模拟p2战斗逻辑&#xff0c;按流程进行步骤拆分&#xff1a; 1.p2抽卡 2.p2召唤怪兽上场 3.p2战斗 其中战斗部分分为几种情况&#xff1a; 情况一&#xff1a;p2场上卡牌由大到小进行排序&#xff0c;按序轮询可以攻击的卡牌&#xff0c;然后攻击p1场上卡牌由大到小…

代码随想录阅读笔记-二叉树【完全二叉树节点个数】

题目 给出一个完全二叉树&#xff0c;求出该树的节点个数。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,4,5,6]输出&#xff1a;6 示例 2&#xff1a; 输入&#xff1a;root []输出&#xff1a;0 示例 3&#xff1a; 输入&#xff1a;root [1]输出&#xff1a;1 提示&…

玩转Django分页器

一、Pagination 分页器编程步骤 View, 导入django.core.paginator.Paginator类&#xff0c;创建Paginator 对象时&#xff0c;输入qs对象&#xff0c;以及每页显示条数。 接收 URL, 从请求参数中读取page数值 &#xff0c;通过 paginator.page(page_num) 返回请求页的page_obj…

pyinstaller打包多线程pyqt5程序后,报错,反复弹窗等问题

报错1&#xff1a; Traceback (most recent call last): File “MPL.py”, line 502, in File “Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_multiprocessing.py”, line 45, in _freeze_support ValueError: not enough values to unpack (expected 2, got 1) 报…

绘制空心环形

1.通过几个div拼接绘制空心环形进度条。 通过 -webkit-mask: radial-gradient(transparent 150px, #fff 150px);绘制空心圆 html:<body><div class"circle"><div class"circle-left"></div><div class"circle-left-mask&…

从0开始搭建基于VUE的前端项目(二) 安装和配置element-ui组件库

版本和地址 ElementUI 2.15.14 (https://element.eleme.io/)按需引入的插件 babel-plugin-component(1.1.1) https://github.com/ElementUI/babel-plugin-component 安装 npm install element-ui完整引入(不建议) 这种方式最后打包的源文件很大&#xff0c;造成网络资源的浪…