Java 设计模式——原型模式

news2024/11/25 15:26:05

目录

  • 1.概述
  • 2.结构
  • 3.实现
    • 3.1.浅拷贝
    • 3.2.深拷贝
      • 3.2.1.通过对象序列化实现深拷贝(推荐)
      • 3.2.2.重写 clone() 方法来实现深拷贝
  • 4.优缺点
  • 5.使用场景

1.概述

(1)原型模式 (Prototype Pattern) 是一种创建型设计模式,是通过复制(克隆)现有对象来创建新对象的模式。它允许我们创建一个原型对象,然后通过复制该原型对象来创建新的对象,而无需通过实例化类来创建新的对象

(2)在原型模式中,一个类将自身的实例作为原型,通过复制这个原型来创建新的对象。这个过程隐藏了对象的创建细节,而且可以提高创建对象的效率。

(3)原型模式基于对象的复制,可以分为浅拷贝和深拷贝两种形式:

  • 浅拷贝:复制对象时,仅仅复制对象的引用,而不复制对象本身。新对象和原对象共享同一个引用,修改一个对象会影响到另一个对象。
  • 深拷贝:复制对象时,不仅复制对象的引用,还复制对象本身,创建一个独立的对象。新对象和原对象互不影响,修改一个对象不会影响到另一个对象。

(4)在实现原型模式时,通常需要实现一个 Cloneable 接口(或类似的机制),该接口标识类具有复制自己的能力。具体的实现细节则根据语言和框架的不同而有所差异。

2.结构

(1)原型模式包含如下角色:

  • 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

(2)接口类图如下:
在这里插入图片描述

3.实现

Java 中的 Object 类中提供了 clone() 方法来实现浅克隆Cloneable 接口是上面的类图中的抽象原型类,而实现了 Cloneable 接口的子实现类就是具体的原型类。

3.1.浅拷贝

Address.java

public class Address {
    int id;
    String addressName;
    
    public Address(int id, String addressName) {
        this.id = id;
        this.addressName = addressName;
    }
}

Person.java

public class Person implements Cloneable{
    private int id;
    private String name;
    private Address address;
    
    public String getName() {
        return name;
    }
    
    public Person(int id, String name, Address address) {
        this.id = id;
        this.name = name;
        this.address = address;
        System.out.println("具体的原型对象创建完成!");
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        return (Person) super.clone();
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
    
}

Client.java

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person(1, "小华", new Address(1, "北京"));
        Person person2 = (Person) person1.clone();
        System.out.println("person1: " + person1);
        System.out.println("person2: " + person2);
        System.out.println("person1.getName() == person2.getName() 的结果为: " + (person1.getName() == person2.getName()));
        System.out.println("person1 == person2 的结果为: " + (person1 == person2));
    }
}

输出结果如下图所示:

在这里插入图片描述

3.2.深拷贝

3.2.1.通过对象序列化实现深拷贝(推荐)

先将 Address 类和 Person 类实现 Serializable 接口,然后再修改 Client.java 中的代码即可。

Client.java

public class Client {
    public static void main(String[] args) throws Exception {
        Person person1 = new Person(1,"小华",new Address(1,"北京"));
    
        //创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\testData\\a.txt"));
        //写对象
        oos.writeObject(person1);
        //释放资源
        oos.close();
    
        //创建对象输入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\testData\\a.txt"));
        //读取对象
        Person person2 = (Person) ois.readObject();
        //释放资源
        ois.close();
        
        System.out.println("person1:"+person1);
        System.out.println("person2:"+person2);
        System.out.println("person1.getName() == person2.getName()的结果为:"+(person1.getName() == person2.getName()));
        System.out.println("person1 == person2的结果为:"+(person1 == person2));
    }
}

在这里插入图片描述

3.2.2.重写 clone() 方法来实现深拷贝

public class Person implements Cloneable {
    private int id;
    private String name;
    private Address address;
    
    public String getName() {
        return name;
    }
    
    public Person(int id, String name, Address address) {
        this.id = id;
        this.name = name;
        this.address = address;
        System.out.println("具体的原型对象创建完成!");
    }
    
    @Override
    public Object clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        Person person = null;
        person = (Person)super.clone();
        //对引用数据类型单独处理
        person.name = new String(name);
        person.address = (Address)address.clone();
        return person;
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}

4.优缺点

(1)原型模式具有以下优点:

  • 减少对象的创建成本:原型模式通过复制现有对象来创建新对象,避免了使用构造函数的开销,提高了对象的创建效率。
  • 简化对象的创建过程:使用原型模式,不需要关心对象的具体实现细节,只需复制一个现有对象即可得到新的对象,简化了对象的创建过程。
  • 支持动态添加和修改对象的属性:可以通过修改现有对象的属性来创建新对象,避免了在代码中显式设置对象属性的麻烦。
  • 提供了一种可扩展的创建方式:原型模式通过复制现有对象,可以创建出多个具有相同属性的对象,也可以根据需要修改部分属性,从而具有更高的灵活性和可扩展性。

(2)原型模式也存在一些缺点:

  • 需要实现 Cloneable 接口或类似的机制:在一些语言和框架中,实现原型模式需要实现 Cloneable 接口或类似的机制,这对于某些编程语言来说可能需要额外的工作。
  • 深拷贝可能较为复杂:如果需要复制的对象存在引用类型的成员变量,深拷贝可能需要额外的处理来确保所有引用对象也能被正确地复制。
  • 对象复杂性限制:对于包含循环引用或复杂对象图的对象,可能会导致复制过程变得复杂或不可行。

(3)综上所述,原型模式在某些情况下可以提供高效、灵活和可扩展的对象创建方式,但使用时需注意克隆的实现细节和对象的复杂性。

5.使用场景

(1)原型模式适用于以下场景:

  • 对象创建成本高:当对象的创建成本较高时,例如需要进行复杂的计算、数据读取或网络请求等操作,可以使用原型模式复制现有对象来提高创建效率。
  • 对象初始化复杂:当对象的初始化过程较为复杂,包含多个步骤或依赖关系较多时,可以使用原型模式来复制一个已经初始化好的对象,避免重新执行初始化过程。
  • 动态创建和定制对象:当需要根据一些条件动态创建和定制对象时,原型模式可以提供一种更加灵活的创建方式。通过复制现有对象并根据需要修改部分属性,即可创建出符合条件的新对象。
  • 避免构造函数调用:在某些场景下,使用构造函数创建对象可能不可行或不符合需要。例如,某些框架中对象的创建由框架负责,通过原型模式可以避免直接调用构造函数。
  • 对象的状态变化较小:当对象的状态变化较小,只是部分属性需要修改时,使用原型模式可以避免重新创建对象,提高了性能。

(2)总的来说,原型模式适用于需要复制和创建新对象的场景,尤其是在对象的创建成本较高或初始化复杂的情况下,使用原型模式可以提高创建效率和灵活性。

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

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

相关文章

【2023裸辞失业后之初学RocketMQ】

目录 RocketMQ概述MQ概述常见的MQ产品常见的协议 Rocket的安装和启动基本概念系统架构安装RocketMQ和控制台 RocketMQ概述 MQ概述 Message Queue:是提供消息队列服务的中间件,提供消息生产,存储,消费的全过程。 作用&#xff1a…

刘铁猛C#语言教程——表达式详解1

表达式的定义 对以上文档的翻译: 对以上文档的代码解释:表达式是为了实现具体的算法逻辑并得到一个具体的值,而表达式的返回值可以是一个单值,也可以是实例,方法,或者命名空间;例如:…

微服务入门---SpringCloud(一)

微服务入门---SpringCloud(一) 1.认识微服务1.0.学习目标1.1.单体架构1.2.分布式架构1.3.微服务1.4.SpringCloud1.5.总结 2.服务拆分和远程调用2.1.服务拆分原则2.2.服务拆分示例2.2.1.导入Sql语句2.2.2.导入demo工程 2.3.实现远程调用案例2.3.1.案例需求…

当今网络的基本情况

1 网络表示方法和网络拓扑 1.1 网络表示方法 网络架构师和管理员必须能够展示他们的网络将是什么样子。他们需要能够轻松地看到哪些组件连接到其他组件,它们将位于何处,以及它们将如何连接。网络图通常使用图标(如图中所示)来表…

基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法

文献计量学是指用数学和统计学的方法,定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体,注重量化的综合性知识体系。特别是,信息可视化技术手段和方法的运用,可直观的展示主题的研究发展历程、研究现状、研究…

数据结构与算法-排序算法

数据结构与算法之排序算法 1 使用递归的方式求最大值2 时间复杂度3 选择排序和冒泡排序的时间复杂度分析4 插入排序时间复杂度分析 (O(N^2))5 二分法的详解与扩展6 对数器7 归并排序8 归并排序的应用9 逆序对问题10 归并排序非递归方式11 快速排序12 堆排序13 桶排序 1 使用递归…

并行计算-OPENMP(windows)

并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程,是提高计算机系统计算速度和处理能力的一种有效手段。它的基本思想是用多个处理器来协同求解同一问题,即将被求解的问题分解成若干个部分,各…

深度学习(一)

目录 一、特征工程的作用 二、深度学习的应用 三、得分函数 四、损失函数 五、前向传播 六、反向传播 一、特征工程的作用 数据特征决定了模型的上限预处理和特征提取是最核心的算法与参数选择决定了如何逼近这个上限 二、深度学习的应用 无人驾驶人脸识别分辨率重构 深…

国产龙芯2k1000开发板运行SylixOS嵌入式实时系统--迅为电子

龙芯生态体系越来越完善,继RK3568开发板成功搭载SylixOS国产实时操作系统后,迅为的国产龙芯2K1000开发平台也可以流畅运行SylixOS国产实时操作系统了。 SylixOS 采用抢占式、多任务、硬实时的方式来设计整个操作系统。已广泛适用于电力、工业自动化、轨道…

为什么要配置环境变量(深析)

为什么要配置环境变量(深析) 前言:大家学习java首先听到的就是jdk,配置环境变量,当时我听到这个也一脸雾水,这是个什么东西,当时就稀里糊涂跟着老师一步步下载安装,弄好了也不知道是…

安全基础 --- html基础标签 + DNS工作原理

html基础标签 &#xff08;1&#xff09;id id属性是元素在网页内的唯一标识符。 比如&#xff0c;网页可能包含多个<p>标签&#xff0c;id属性可以指定每个<p>标签的唯一标识符。 <p id"p1"></p> <p id"p2"></p>…

UE4/5C++多线程插件制作(十四、MTPAbandonable)

MTPAbandonable 在头文件中创建新的文件夹,MTPAbandonable,里面是MTPAbandonable.h,cpp也一样如此: h实现 构造函数接受一个FSimpleDelegate类型的参数InThreadDelegate,用于指定任务在后台线程中执行时要执行的操作。 DoWork()函数定义了任务的具体执行逻辑,需要根据…

NLog同时输出到文件、控制台、RichTextBox

效果 项目 VS2010.net4.0NLogNLog.Windows.Forms 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using NLog;namespac…

【Docker 网络】

文章目录 一、Docker 网络1、Docker 网络实现原理2、查看容器的输出和日志信息3、Docker 的网络模式4、网络模式详解1&#xff0e;host模式2&#xff0e;container模式3&#xff0e;none模式4&#xff0e;bridge模式5&#xff0e;自定义网络1、创建自定义网络 二、资源控制1&am…

初识TDMQ

目录 一&#xff1a;需求背景二&#xff1a;相关文档三&#xff1a;验证TDMQ广播消息 一&#xff1a;需求背景 目前公司需要将决策引擎处理的结果&#xff0c; 一部分数据交给下游分析/入黑/通知等功能。因此就需要决策引擎生产结果让多方下游去消费。 而我需要实现下游的一部…

数据类型的分类

数据类型的分类 java中的 变量 按照数据类型来分类&#xff1a; 基本数据类型&#xff08;8种&#xff09;&#xff08;primitive type&#xff09;&#xff1a; 整型&#xff1a;byte、short、int、long、浮点型&#xff1a;float、double字符型&#xff1a;char布尔型&#x…

/var/empty/sshd must be owned by root and not group or world-writable

/var/empty/sshd must be owned by root and not group or world-writable 这个是权限的问题 可采取以下两步解决 chown -R root.root /var/empty/sshd chmod 744 /var/empty/sshd service sshd restart

80v转5v芯片-电动车/汽车降压芯片方案

Q: 什么是80v转5v芯片&#xff1f;什么它在电动车和汽车中有应用需求&#xff1f; A: 80v转5v芯片是一种电源转换芯片&#xff0c;可以将输入电压范围为9v至100v的直流电源转换为输出电压为5v&#xff0c;并且可以进行可调。这种芯片在电动车和汽车领域有广泛的应用需求。电动…

Python+pytest+requests 自动化测试框架

目录 前言&#xff1a; 环境准备 简单 Demo yml 文件读取功能 数据层 业务层 测试用例层 前言&#xff1a; Python 是一种广泛使用的编程语言&#xff0c;它可以用于开发各种软件和应用程序。pytest 是一个广泛使用的自动化测试框架&#xff0c;它可以帮助我们更轻松地…

【Java】如何理解 Spring 核心概念: 什么是 IoC, 什么是 DI?

文章目录 前言一、什么是Spring1, 什么是容器2, 什么是IoC 二、如何理解IoC1, 传统方式的代码编写2, 控制反转的代码编写3, 再谈IoC 三、什么是DI总结 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; JavaSE基础: 基础语法, 类和对象,…