Java基础:设计模式之原型模式

原型模式是一种创建型设计模式,它允许我们通过复制现有的对象来创建新的对象,而不是每次都通过构造函数新建。这种模式适用于那些创建新对象成本较高或者构造过程复杂的情况。在原型模式中,一个对象通过实现Cloneable接口并重写其clone()方法来作为原型。当需要创建新对象时,客户端代码请求原型对象克隆自身,返回一个与原对象状态相同的新对象。

结构与参与者
  1. Prototype(原型): 这是一个接口或抽象类,声明了克隆自己的方法(通常是clone())。所有具体原型类都必须实现这个接口或继承这个抽象类。

  2. ConcretePrototype(具体原型): 实现了Prototype接口或继承了抽象原型类的具体类。它们实现了clone()方法以创建自己的副本(克隆)。

工作流程
  1. 客户端 需要新对象时,不是直接调用构造函数创建,而是请求一个已存在的原型对象克隆自身。

  2. 原型对象 通过实现Cloneable接口,并重写Object类中的clone()方法来提供克隆能力。clone()方法通常会创建一个新的对象,并将当前对象的状态(属性值)复制到新对象中。

  3. 新对象 作为原型对象的副本被返回给客户端,新对象与原型对象状态相同但不共享任何引用数据(除非在深复制中特殊处理)。

适用场景
  1. 对象创建成本高:如果创建一个对象需要大量计算、消耗大量资源(如数据库查询、网络通信、复杂的初始化逻辑等),原型模式可以快速复制已有对象,避免重复高昂的创建成本。

  2. 对象初始化过程复杂:当对象的初始化涉及许多步骤、依赖关系或者权限控制时,使用原型模式可简化创建过程,只需克隆已配置好的原型即可。

  3. 需要大量相似对象:在系统中需要大量具有相同或相似属性的对象,但又不希望引入额外的开销(如频繁的构造函数调用),可以通过复制少量原型对象来生成大量实例。

  4. 保护性拷贝:当一个对象需要提供给多个调用者使用,且调用者可能需要修改对象的属性,通过原型模式可以为每个调用者提供对象的一个独立副本,防止相互干扰。

示例说明
import java.util.Date;

// 原型接口
interface Prototype {
    Prototype clone();
}

// 具体原型类:员工信息
class Employee implements Prototype {
    private String name;
    private int id;
    private Date hireDate;

    // 构造函数和常规setter/getter省略...

    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone(); // 调用Object的clone方法进行浅复制
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("Clone not supported", e);
        }
    }
}

// 客户端代码
public class PrototypeDemo {
    public static void main(String[] args) {
        // 创建一个原型员工对象
        Employee original = new Employee("Alice", 1, new Date());

        // 使用原型模式克隆出新员工
        Employee cloned = original.clone();

        // 改变克隆员工的信息
        cloned.setName("Bob");

        System.out.println("Original employee: " + original.getName());
        System.out.println("Cloned employee: " + cloned.getName());
    }
}

在这个例子中,Employee类实现了Prototype接口并提供了clone()方法。客户端代码通过调用original.clone()快速创建了一个与原对象状态相同的cloned对象。之后修改cloned对象的名称不会影响到原始对象。

存在的问题
  1. 深拷贝与浅拷贝问题:Java中的clone()方法默认执行浅拷贝,即只复制对象本身及其基本类型字段,对于引用类型字段,只是复制了引用,导致原对象和克隆对象共享同一份引用所指向的数据。在某些场景下,这可能导致意外的数据修改。若需完全复制引用类型字段的内容(深拷贝),需要在clone()方法中手动复制这些字段。

  2. Cloneable接口不强制约束:Java的Cloneable接口没有定义任何方法,只是一个标记接口,表明该类支持被克隆。但如果不重写Objectclone()方法并抛出CloneNotSupportedException,则直接调用clone()会抛出异常。这种设计可能导致不符合预期的行为,需要开发者明确了解并正确实现克隆逻辑。

  3. 代码侵入性:为了实现原型模式,需要修改类以实现Cloneable接口并重写clone()方法,这可能对已有代码产生一定侵入性,特别是对于那些原本不需要支持克隆的类。

  4. 错误使用可能导致内存浪费:如果频繁地克隆大对象或含有大量数据的集合,且实际场景并不需要这么多对象副本,可能会造成不必要的内存消耗。

  5. 线程安全问题:在多线程环境中,如果没有正确同步原型对象的访问和克隆过程,可能会导致数据不一致或并发问题。

综上所述,虽然原型模式在特定场景下能有效提高对象创建效率,但使用时需谨慎权衡其带来的复杂性、潜在风险以及对系统设计的影响。在实际应用中,可能还需要结合工厂方法、单例模式等其他创建型模式来优化对象创建过程。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

验证二叉搜索树 - LeetCode 热题 43

大家好!我是曾续缘😘 今天是《LeetCode 热题 100》系列 发车第 43 天 二叉树第 8 题 ❤️点赞 👍 收藏 ⭐再看,养成习惯 验证二叉搜索树 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。 有效 二叉搜…

【Linux】什么是yum?--linux中的软件包管理器详解

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …

UML——类图详解

目录 1. 前言 2. 类图概述 3. 类图表示法 3.1 类的表示方式 3.2 类与类之间关系的表示方式 (1)继承(泛化)关系 (2)实现关系 (3)依赖关系 (4)一般关联关系 (5)聚合关系 (6)组合关系 1. 前言 UML全称(Unified Modeling Language),译为统一建模语言&#x…

FRPC+PHP+MYSQL+APACHE2=个人网站

应用背景有公网需求,但是又不想去买又贵又低配置的服务器,然后方案就应运而生 frp/README_zh.md at dev fatedier/frp (github.com) 在这里, FRPC作为内网穿透服务, PHPMYSQLAPACHE2,作为网站搭建,具体细节不细讲, 但是在我的/var/www/html下面 linaroHinlink:/var/www/h…

代码随想录算法训练营Day8 | ● 344.反转字符串● 541. 反转字符串II● 54.替换数字● 151.翻转字符串里的单词● 55.右旋转字符串

(记得重学) ● 344.反转字符串 题目:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一…

【蓝桥杯2025备赛】集合求和

集合求和 题目描述 给定一个集合 s s s(集合元素数量 ≤ 30 \le 30 ≤30),求出此集合所有子集元素之和。 输入格式 集合中的元素(元素 ≤ 1000 \le 1000 ≤1000) 输出格式 s s s 所有子集元素之和。 样例 #1 …

JAVAEE—HTTP

文章目录 HTTP导读HTTP解析HTTP的格式分析环境准备 HTTP请求格式首行headerHostContent-LengthContent-TypeUser-Agent (简称 UA)RefererCookie 空行body HTTP响应格式认识HTTP的方法POST方法POST和GET的区别第一:用处第二:传递数据第三:GET不…

【漏洞复现】通天星CMSV6车载监控平台Logger未授权漏洞

漏洞描述: 通天星CMSV6车载定位监控平台拥有以位置服务、无线3G/4G视频传输、云存储服务为核心的研发团队,专注于为定位、无线视频终端产品提供平台服务,通天星CMSV6产品覆盖车载录像机、单兵录像机、网络监控摄像机、行驶记录仪等产品的视频…

Sylar C++高性能服务器学习记录05 【线程模块-知识储备篇】

早在19年5月就在某站上看到sylar的视频了,一直认为这是一个非常不错的视频,还有幸加了sylar本人的wx,由于本人一直是自学编程,基础不扎实,也没有任何人的督促,没能坚持下去,每每想起倍感惋惜。恰…

Android IPC | Android多进程模式

前 言 关于Android的进程间通信(即IPC)有很多种方式,比如我们常用的AIDL、Socket等,而其中最重要而且最需要掌握的就是AIDL的使用和原理,简单来说它是通过Binder实现的。 关于Binder的知识点非常多,当我们…

libtorrent - 安装小记

文章目录 官方文档:libtorrent python binding http://libtorrent.org/python_binding.html 1、下载代码 建议使用: git clone --recurse-submodules https://github.com/arvidn/libtorrent.git如果在 github web 界面下载代码,build 的时候…

sentinel-1.8.7与nacos-2.3.0实现动态规则配置、双向同步

😊 作者: 一恍过去 💖 主页: https://blog.csdn.net/zhuocailing3390 🎊 社区: Java技术栈交流 🎉 主题: sentinel-1.8.7与nacos-2.3.0实现动态规则配置、双向同步 ⏱️ 创作时…

FL Studio21.2中文破解版下载2024最新五月破解步骤教程

FL Studio 21.2.3.4004中文版 中文别名水果编曲软件,是一款全能的音乐制作软件,包括编曲、录音、剪辑和混音等诸多功能,让你的电脑编程一个全能的录音室,它为您提供了一个集成的开发环境,使用起来非常简单有效&#xf…

MATLAB命令

MATLAB是一个用于数值计算和数据可视化的交互式程序。您可以通过在命令窗口的MATLAB提示符 ‘>>’ 处键入命令来输入命令。 在本节中,我们将提供常用的通用MATLAB命令列表。 用于管理会话的命令 MATLAB提供了用于管理会话的各种命令。下表提供了所有此类命令…

基于springboot+vue+Mysql的CSGO赛事管理系统

开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…

京东商品差评获取

1.背景 场景一:一个市场研究员或者是一个企业的产品经理,需要下载差评来了解消费者对于某一产品或者服务的不满,以便改进他们的产品或服务。 场景二:一个人是某个企业的竞争对手,需要下载差评来了解他们的竞争对手的…

java自动生成pojo,springboot自动生成pojo

第一步 pom引入依赖 <dependencies><!-- mybatis-generator --><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.7</version></dependency>&…

乒乓球廉价底板及套胶评测5

今天给同事贴一个银河t2底板&#xff0c;正手狂39度&#xff0c;反手拍里奥&#xff0c;银河t2是碳板&#xff0c;考虑到使用的长期性&#xff0c;没有灌油&#xff0c;用的无机胶水。 这套装备本身没有什么瑕疵&#xff0c;主要还是考虑正手狂三的通透性&#xff0c;我认为有…

QML 中的状态

Qt hello – 专注于Qt的技术分享平台 状态描述了当前用户界面样子&#xff0c;QML中一个状态定义了一组属性的改变&#xff0c;并且会在一定条件下被触发。 假设有这么一个场景&#xff0c;红黄绿三个灯&#xff0c;用一个按钮&#xff0c;点击后依次切换三个灯亮起。使用QWi…

【C++干货基地】深度理解C++中的高效内存管理方式 new delete

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…
最新文章