三、原型模式

news2024/11/30 8:32:38

一、什么是原型模式

  原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。原型模式包含以下主要角色。

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

二、原型模式的实现

  深克隆与与浅克隆:Object类的clone方法只会克隆对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会克隆,这就是浅克隆。如果要实现深克隆,必须将原型模式中的数组、容器对象、引用对象等另行克隆。
  由于 Java 提供了对象的 clone() 方法,所以用 Java 实现原型模式很简单。
1、创建Prototype的成员属性:


/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2021-03-31 0:12
 * @description Prototype的成员变量
 */
public class Member implements Cloneable{
    private String position;

    public Member(String position) {
        this.position = position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }


    @Override
    public String toString() {
        return "Member{" +
                "position='" + position + '\'' +
                '}';
    }
}

2、创建具体原型类Prototype:



import java.util.ArrayList;

public class Prototype implements Cloneable{
    private String name ;
    private int age;
    private ArrayList<String> hobbies;
    private Member member;

    public Prototype(String name, int age, ArrayList<String> hobbies, Member member) {
        this.name = name;
        this.age = age;
        this.hobbies = hobbies;
        this.member = member;
        System.out.println("通过构造方法创建对象。。。。。。");
    }

    /**
     * 浅克隆
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    /**
     * 深克隆
     */
//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        Prototype clone = (Prototype) super.clone();
//        clone.setHobbies((ArrayList<String>) clone.getHobbies().clone());
//        clone.setMember((Member) clone.getMember().clone());
//        return clone;
//    }

    public void setName(String name){
        this.name = name;
    }

    public void setHobbies(ArrayList<String> hobbies) {
        this.hobbies = hobbies;
    }

    public ArrayList<String> getHobbies() {
        return hobbies;
    }

    public Member getMember() {
        return member;
    }

    public void setMember(Member member) {
        this.member = member;
    }

    @Override
    public String toString() {
        return "Prototype{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", hobbies=" + hobbies +
                ", member=" + member +
                '}';
    }
}

3、创建测试类(访问类):


import java.util.ArrayList;

/**
 * 原型模式
 *  原型模式的定义与特点:
 *      原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,
 *      原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,
 *      如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。
 *      原型模式的结构与实现由于 Java 提供了对象的 clone() 方法,所以用 Java 实现原型模式很简单。
 *  模式的结构
 *      原型模式包含以下主要角色。
 *      抽象原型类:规定了具体原型对象必须实现的接口。   (Cloneable)
 *      具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。  (Prototype)
 *      访问类:使用具体原型类中的 clone() 方法来复制新的对象。  (Main.class)
 */
public class Main {

    @Test
    public void prototypeTest() throws CloneNotSupportedException {
        Member initMember = new Member("c#");
        ArrayList<String> initHobbies = new ArrayList<>();
        initHobbies.add("play");
        Prototype prototype = new Prototype("张三",18,initHobbies,initMember);
        System.out.println("复制前");
        System.out.println("被克隆对象:"+prototype);
        Prototype prototype1 = (Prototype) prototype.clone();
        System.out.println("复制后");
        System.out.println("是否同一对象:"+(prototype==prototype1?"是":"否"));
        System.out.println("修改被克隆对象属性:");

        prototype.setName("李四");
        initHobbies.add("eat");
        initMember.setPosition("java");

        System.out.println("被克隆对象:"+prototype);
        System.out.println("克隆出的对象:"+prototype1);

    }

}
  • 当把深克隆的实现方法注释,使用浅克隆的方法时

image.png

运行结果:


通过构造方法创建对象。。。。。。
复制前
被克隆对象:Prototype{name='张三', age=18, hobbies=[play], member=Member{position='c#'}}
复制后
是否同一对象:否
修改被克隆对象属性:
被克隆对象:Prototype{name='李四', age=18, hobbies=[play, eat], member=Member{position='java'}}
克隆出的对象:Prototype{name='张三', age=18, hobbies=[play, eat], member=Member{position='java'}}

  当修改被克隆对象hobbies与member属性的时候,克隆出来对象的hobbies与member属性也被修改,可见这两个属性都是同一对象引用,而String类型的name以及基础类型的age属性是不会被同时修改的,可见不是同一引用。浅克隆只复制对象的String类型属性以及一些基本类型属性,是不完全克隆。

  • 当把浅克隆的实现方法注释,使用深克隆的方法时

image.png

运行结果:


通过构造方法创建对象。。。。。。
复制前
被克隆对象:Prototype{name='张三', age=18, hobbies=[play], member=Member{position='c#'}}
复制后
是否同一对象:否
修改被克隆对象属性:
被克隆对象:Prototype{name='李四', age=18, hobbies=[play, eat], member=Member{position='java'}}
克隆出的对象:Prototype{name='张三', age=18, hobbies=[play], member=Member{position='c#'}}

  当修改被克隆对象name、age、hobbies以及member属性的时候,克隆出来对象的hobbies与member属性并未被修改,可见通过这种深克隆的方法,把所有的属性都创建一个新的内存对象,并使被克隆对象与克隆出的对象所有属性有不同的地址引用,深克隆的复制更加彻底。

  注意:上面代码在执行克隆的时候并未打印构造方法中的:“通过构造方法创建对象。。。。。。”,因此可见,使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。还记得单例模式吗?单例模式中,只要将构造方法的访问权限设置为private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的,在使用时要特别注意。

三、应用场景

  原型模式通常适用于以下场景。

  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 创建对象成本较大,例如初始化时间长,占用CPU太多,或者占用网络资源太多等,需要优化资源。
  • 创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性。
  • 系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。

四、优缺点分析

  原型模式的优点

  • Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
  • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

  原型模式的缺点

  • 需要为每一个类都配置一个 clone 方法
  • clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
  • 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。

代码地址:https://gitee.com/fluffycatkin/JavaDesignModel.git

image.png

原文出处:
https://blog.csdn.net/zhengzhb/article/details/7393528
http://c.biancheng.net/view/1343.html

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

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

相关文章

数据结构 day6

1->xmind 2->递归实现程序&#xff1a;输入一个数&#xff0c;输出该数的每一位

【哈士奇赠书活动 - 37期】- 〖深入浅出SSD:固态存储核心技术、原理与实战 第2版〗

文章目录 ⭐️ 赠书 - 《深入浅出SSD&#xff1a;固态存储核心技术、原理与实战 第2版》⭐️ 内容简介⭐️ 作者简介⭐️ 编辑推荐⭐️ 赠书活动 → 获奖名单 ⭐️ 赠书 - 《深入浅出SSD&#xff1a;固态存储核心技术、原理与实战 第2版》 ⭐️ 内容简介 本书从基础认知、核心技…

Mac版JFormDesigner IDEA插件安装(非商业用途)

前言 仅供个人开发者使用&#xff0c;勿用作商业用途。 仅供个人开发者使用&#xff0c;勿用作商业用途。 仅供个人开发者使用&#xff0c;勿用作商业用途。 感觉做了这些年开发&#xff0c;怎么感觉市场越搞越回去了。桌面应用又成主流了&#xff1f; 甲方让做桌面客户端&am…

【微服务部署】一、使用docker-compose部署Jenkins、SonarQube、PostgreSQL

一、安装 1、编写docker-compose部署Postgres、SonarQube、Jenkins的yml文件jenkins-compose.yml Postgres&#xff1a;作为SonarQube的数据库存储SonarQube&#xff1a;代码质量检查Jenkins&#xff1a;jenkins/jenkins:lts镜像&#xff0c;jenkinsci/blueocean镜像缺少node…

ELK安装、部署、调试 (二) ES的安装部署

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口操作ES&#xff0c;也可以利用Java API。Elasticsearch是用Java开发的&#xff0c;并作为Apache许可条款下的开放源码发布&#xff0c;是当前流行的企业…

linux安装docker全过程

3. 第二步&#xff1a;设置docker的存储库。就两条命令&#xff0c;我们直接执行就好。 ​ sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo ​​ 4. 安装docker engine和docker-compose。 执行命…

WebSocket--技术文档--架构体系--《WebSocket实现原理以及关键组件》

WebSocket产生背景 简单的说&#xff0c;WebSocket协议之前&#xff0c;双工通信是通过多个http链接来实现&#xff0c;这导致了效率低下。WebSocket解决了这个问题。下面是标准RFC6455中的产生背景概述。 长久以来, 创建实现客户端和用户端之间双工通讯的web app都会造成HTT…

4.6 审阅与共享演示文稿

本节主要学习了审阅与共享演示文稿的方法&#xff0c;让用户学会审查制作好的演示文稿&#xff0c;并分享给其他人。 4.6.1 审阅演示文稿 当需要对其他人制作的演示文稿进行修改时&#xff0c;可使用添加批注功能&#xff0c;这样能在不改动原有幻灯片的情况下&#xff0c;使…

MAC修改python3命令为py

1, 找到python3安装路径 2, vi ~/.bash_profile 3, 增加内容: alias py“/usr/bin/python3” 4, 重载source ~/.bash_profile 5,执行py

onnx模型修改:将均值和方差放到模型中

训练模型时&#xff0c;一般都会对原始数据进行归一化再送入网络&#xff0c;即减均值和除方差。在部署时&#xff0c;我们也要进行同样的操作。有些推理框架会提供对应的接口&#xff0c;我们只需要设置均值和方差即可&#xff0c;如MNN.也有一些框架不提供这样的功能&#xf…

单元测试:优雅编写Kotlin单元测试

一、MockK简介 MockK是一款功能强大、易于使用的Kotlin mocking框架。在编写单元测试时&#xff0c;MockK能够帮助我们简化代码、提高测试覆盖率&#xff0c;并改善测试的可维护性。除了基本用法外&#xff0c;MockK还提供了许多额外的功能和灵活的用法&#xff0c;让我们能够…

剑走偏锋:非传统问题在面试中的应对策略

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

如何优雅地在windows上玩ROS(一个紧致的解决方案)

如何优雅地在windows上玩ROS&#xff08;一个紧致的解决方案&#xff09; - 知乎 Excerpt 前言为了节省您的时间&#xff0c;本文适用的OS为win10&#xff0c;win11&#xff1b;适用的ROS1版本为melodic和noetic&#xff1b;适用于ROS2 foxy。如果你的目标OS和ROS不在上述的范围…

雅思写作 三小时浓缩学习顾家北 笔记总结(一)

目录 饥饿网翻译100个句子记录 There are some economically deprived communities in large cities. there is no clear link between grouping student by ability and their levels of attainment. young people without tertiary education qualification normally hav…

java八股文面试[数据库]——索引的基本原理、设计原则

索引的设计原则 索引覆盖是什么&#xff1a; 索引&#xff08;在MySQL中也叫做“键&#xff08;key&#xff09;”&#xff09; 是存储引擎用于快速找到记录的一种数据结构。这是索引的基本功能。 索引对于良好的性能非常关键。尤其是当表中的数据量越来越大时&#xff0c;索引…

成集云 | 钉钉财务费用单同步至畅捷通 | 解决方案

源系统成集云目标系统 方案介绍 财务管理作为企业管理中重要的组成部分&#xff0c;在企业的发展和成长中扮演着重要角色&#xff0c;成集云以钉钉费用单OA审批与畅捷通TCloud系统为例&#xff0c;与钉钉连接器深度融合&#xff0c;通过数据处理和字段匹配实现了费用…

【LeetCode】290. 单词规律

这里写自定义目录标题 2023-8-30 09:34:23 290. 单词规律 2023-8-30 09:34:23 这道题目&#xff0c;我是根据 205. 同构字符串 的思路一样&#xff0c;都转化为另外一个第三方的字符串&#xff0c;在比较翻译过后的语句是不是一样的。 class Solution {public boolean wordP…

自然语言处理的多行业应用

在我们小时候&#xff0c;甚至是我们会走路或说话之前&#xff0c;就已经在察觉周围发出的声音了。我们倾听其他人发出的声响和声音。我们将声音组合成有意义的词语&#xff0c;例如“母亲”和“门”&#xff0c;并学习解读周围人的面部表情&#xff0c;以加深我们对词组的理解…

火爆全网!HubSpot CRM全面集成,引爆营销业绩!

HubSpot CRM是什么&#xff1f;它是一款强大的客户关系管理工具&#xff0c;专为企业优化销售、服务和市场营销流程而设计。它在B2B行业中扮演着极为重要的角色&#xff0c;让我来告诉你为什么吧&#xff01; HubSpot CRM不仅拥有用户友好的界面和强大的功能&#xff0c;还能够…

Dimensions网站——一个链接研究知识系统

Dimensions网站——一个链接研究知识系统 一、Dimensions网站简介 Dimensions 是一个链接的研究知识系统&#xff0c;它重新构想了发现和研究的获取。Dimensions 由 Digital Science 与全球 100 多个领先研究组织合作开发&#xff0c;汇集了资助、出版物、引文、替代指标、临…