通俗易懂的java设计模式(7)-原型模式

news2024/12/27 10:50:05

1.什么是原型模式?

原型模式提供了一种创建对象的模式,它是指用原型实例创建对象的种类,并且通过拷贝这些原型,创建新的对象。用一个很生动形象的例子:孙悟空拔出一根猴毛,变出其他和自己一模一样的小孙悟空,在这里,原型实例就是孙悟空,拔出的猴毛通过拷贝孙悟空的外表特征,变成了其他小孙悟空。

如何实现?

在java中通过实现 实现 Cloneable 接口,并且重写clone方法,在创建新对象时候,调用原型实例.clone()

2.简单的代码实现

克隆羊多莉大家一定听说过吧,那么就用多利羊来说明这个原型模式吧

首先创建出一个羊的实例对象,去实现Cloneable 接口

public class Sheep implements Cloneable{
    private String name;
    private int age;

    public Sheep(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Object clone(){
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
        return clone;
    }

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

测试一下原型模式创建对象

public class Test {
    public static void main(String[] args){ 
        Sheep sheep = new Sheep("Dolly", 1);

        Sheep duoli1 = (Sheep) sheep.clone();
        Sheep duoli2 = (Sheep) sheep.clone();
        Sheep duoli3 = (Sheep) sheep.clone();

        System.out.println("duoli1:"+duoli1+"hashcode:"+duoli1.hashCode());
        System.out.println("duoli2:"+duoli2+"hashcode:"+duoli2.hashCode());
        System.out.println("duoli3:"+duoli3+"hashcode:"+duoli3.hashCode());
    }
}

请添加图片描述

3浅拷贝VS深拷贝

3.1浅拷贝

基本数据类型的成员变量:将属性值复制一份给新的对象,是值传递

引用数据变量的成员变量:将该成员变量的地址值复制一份给新的对象,是地址传递,也就是说,不管在哪个对象中修改这个成员变量,都会影响到另一个对象中该成员变量的值。

浅拷贝默认的实现就是.clone()方法

下面就来进行一个测试,在Sheep类中新增一个person类,代表羊的主人

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

在Sheep类中增加上这个person

请添加图片描述

测试

public class Test {
    public static void main(String[] args){
        Person master = new Person("多莉的主人");
        Sheep sheep = new Sheep("Dolly", 1,master);

        Sheep duoli1 = (Sheep) sheep.clone();
        Sheep duoli2 = (Sheep) sheep.clone();
        Sheep duoli3 = (Sheep) sheep.clone();

        System.out.println("duoli1:"+duoli1+"hashcode:"+duoli1.hashCode()+"master:"+duoli1.getPerson().hashCode());
        System.out.println("duoli2:"+duoli2+"hashcode:"+duoli2.hashCode()+"master:"+duoli2.getPerson().hashCode());
        System.out.println("duoli3:"+duoli3+"hashcode:"+duoli3.hashCode()+"master:"+duoli2.getPerson().hashCode());
    }
}

请添加图片描述

3.2深拷贝

基本数据类型的成员变量:值传递

引用数据类型的成员变量:对整个对象进行拷贝,包括对象的引用类型,不再是拷贝地址了

clone()默认是浅拷贝,那么如何实现深拷贝呢?

方法一:重写clone方法

方法二:通过对象序列化实现

方式一实现起来非常简答,只需要Person也去实现Cloneable接口,并且重写clone方法,然后在修改Sheep的clone方法即可

Person的clone方法

@Override
    protected Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
        return clone;
    }

重写Sheep的clone方法

@Override
    protected Object clone(){
        Sheep clone = null;
        try {
            //转换为Sheep
            clone = (Sheep) super.clone();
            //person也克隆过来
            clone.setPerson((Person) person.clone());
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
        return clone;
    }

重新运行测试

请添加图片描述

方式二:通过序列化实现

①:实现序列化接口

Sheep和Person都要,然后不用再实现Cloneable接口了

public class Sheep implements Serializable 

②:自定义深拷贝方法

public Object deepClone() {
        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); //当前这个对象以对象流的方式输出

            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            Sheep sheep = (Sheep) ois.readObject();

            return sheep;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e2) {
                System.out.println(e2.getMessage());
            }
        }
    }

测试:

public class Test {
    public static void main(String[] args){
        Person master = new Person("多莉的主人");
        Sheep sheep = new Sheep("Dolly", 1,master);

        Sheep duoli1 = (Sheep) sheep.deepClone();
        Sheep duoli2 = (Sheep) sheep.deepClone();
        Sheep duoli3 = (Sheep) sheep.deepClone();

        System.out.println("duoli1:"+duoli1+"hashcode:"+duoli1.hashCode()+"master:"+duoli1.getPerson().hashCode());
        System.out.println("duoli2:"+duoli2+"hashcode:"+duoli2.hashCode()+"master:"+duoli2.getPerson().hashCode());
        System.out.println("duoli3:"+duoli3+"hashcode:"+duoli3.hashCode()+"master:"+duoli3.getPerson().hashCode());
    }
}

请添加图片描述

4.原型模式的优缺点

  • 优点:
    • 如果创建对象的过程十分复杂,使用原型模式可以提高效率
    • 原始对象发生变化,克隆对象也会变化,不用手动修改代码
    • 可以动态地获取对象的状态
  • 缺点
    • 深拷贝代码比较复杂
    • 需要对每一个类准备一个克隆方法,如果是创建的新类,问题不大,但是如果是要修改已有的类,就涉及到修改源代码,违背了ocp原则(需求变化时,尽量通过扩展实体而不是修改源代码来实现)

5.原型模式在java中的应用

spring中的:@Scope(“prototype”)注解,默认值是singleton,也就是单例,但是当值为prototype就意味着对象变成了多例,为每一个线程都提供了一个对象。

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

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

相关文章

Linux三剑客之Sed

目录 一、认识sed 二、使用sed 命令格式 常用选项options 地址定界 编辑命令command sed用法 常用选项: 地址界定演示 编辑命令command演示 sed高级编辑命令 一、认识sed sed 是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行…

《Linux Shell脚本攻略》学习笔记-第九章

9.1 简介 计算机系统是由一组硬件及控制这些硬件的软件组成的。 Linux既提供了能够检查这些系统当前性能的交互式程序,也提供了用于记录一段时间内系统性能表现的模块。 9.2 监视磁盘使用情况 磁盘空间是一种有限的资源。 du和df命令可以报告磁盘使用情况&#xff0…

消息中间件如何选型 图解 Kafka vs RabbitMQ vs RocketMQ 的差异

综述 Kafka 采用拉取 ( Pull) 方式消费消息,吞吐量相对更高,适合海量数据收集与传递场景,例如日志采集和集中分析缺点 Kafka 单机超过 64 个队列/分区,Load 会发生明显的飙高现象,队列越多,load 越高&#…

linux基本功系列之chage命令实战

文章目录前言一. chage命令的介绍二. 常用案例示范1. 查看用户密码的有效期2. 设置密码的过期时间3. 设置账号的失效时间总结前言 前言🚀🚀🚀 想要学好Linux,命令是基本功,企业中常用的命令大约200多个,不管…

2023牛客寒假算法基础集训营1

题解 | #2023牛客寒假算法基础集训营1#_牛客博客 (nowcoder.net) //本人能力有限,以下只附上本人get到的题,其他参考以上链接或其他 A World Final? World Cup! (I) 链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 …

【自学Docker 】Docker top命令

Docker top命令 大纲 docker top教程 使用 docker top 命令可以用来查看 Docker 中运行的进程信息。docker top 命令后面的 CONTAINER 可以是容器 ID,或者是容器名。 docker top语法 haicoder(www.haicoder.net)# docker top [OPTIONS] CONTAINER [ps OPTIONS]案…

说话的三重复杂性

从0开始首先要有一个说话者,这个说话者说出来的话有三重有意。说话者想要表达的东西。文字本身的意义。倾听者所理解的意义。例子:说话者问:有女朋友吗?我们假设说话者要表达,如果还没,那么一起加班。文字本…

GIS入门进阶之017

一、网络分析 网络分析是ArcGIS提供的重要的空间分析功能,利用它可以模拟现实世界的网络问题。如从网络数据中寻找多个地点之间的最优路径,确定网络中资源的流动方向、资源配置和网络服务范围等。 网络是图论和运筹学中的一个数学模型,通常用…

【C#】封装.net framework函数库,并打包发布dll函数库到nuget服务器

作者:小5聊 简介:一只喜欢全栈方向的程序员,专注基础和实战分享,欢迎咨询,尽绵薄之力答疑解惑! 1、Nuget函数库管理工具 1.1、什么是Nuget Nuget是一个.NET平台下的开源的项目,它是Visual Stu…

电脑怎么设置定时关机?分享2个简单操作!

随着互联网时代的发展,越来越多人使用电脑。使用过程中,有时会产生很多疑惑,其中有朋友问小编:电脑怎么设置定时关机?其实Windows系统设置关机很简单,主要有下面两个方法! 演示机型:…

【学习打卡 Free-Excel 】Task1~2 数据源何而来_数据格式

free-excel 文章目录free-excel1 数据基本知识工作簿与工作表xls和xlsx单元格行列导入数据从文件导入数据从网页导入数据:中文编码:2 表格单元格数据类型excel错误提示数据统一添加符号数值转文本、文本转数值资源链接 Free excel_文字版Free excel&…

系分 - 案例分析 - 数据库设计(基本)

个人总结,仅供参考,欢迎加好友一起讨论 文章目录系分 - 案例分析 - 数据库设计(基本)数据库基础数据库设计规范化(范式)数据库事务并发控制典型例题题目描述参考答案数据库安全性技术视图物化视图存储过程触…

【练习】Day07

努力经营当下,直至未来明朗! 文章目录一、选择二、编程1. 不同路径2. 三角形最小路径和 [重点理解!!]答案1. 选择2. 编程普通小孩也要热爱生活! 一、选择 以下关于 Servlet 生命周期说法错误的是 ( ) A: Servlet 容器…

解构模块化区块链

干货:解构模块化区块链 在可扩展性方面,模块化区块链是区块链设计的最新范式。 模块化的概念起源于Layer1区块链Celestia,现在这个概念也逐渐被更多的人所关注,还有人甚至提出”模块化区块链将定义Web3创新的下一个十年“的口号…

java.sql.SQLException: ORA-28001: the password has expired

1、找到SQL Plus 运行 2、登录 请输入户名: sys as sysdba 输入口令:(sys用户的密码)3、以dba角色登入 SQL >connect as sysdba; 请输入户名: sys as sysdba 输入口令:(sys用户的密码)4、修改密码 SQ…

Flink:FlinkSql解析嵌套Json

日常开发中都是用的简便json格式,但是偶尔也会遇到嵌套json的时候,因此在用flinksql的时候就有点麻烦,下面用简单例子简单定义处理下 1,数据是网上摘抄,但包含里常用的大部分格式 { "afterColumns": {…

SpringBoot集成Elasticsearch7.4 实战(一)

在网上已经有好多关于Elasticsearch的介绍,就不在翻来覆去讲一些基本概念,大家感兴趣的可以自己去找一些资料巩固下。这次只为了顾及众多首次接触Elasticsearch,案例都讲的很浅显,还有就是受个人能力所限,各位读者发现…

大数据-hadoop-hdfs

Hadoop分布式文件系统(HDFS)是指被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统(Distributed File System)。它和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。HDFS是一个高度…

数据结构(3)线段树基础

活动 - AcWing 参考《算法竞赛进阶指南》-lyd 一、概述 1.简述、所需空间 线段树是一种基于分治思想的二叉树结构,用于区间上的信息统计。与树状数组相比,线段树是一种更通用的数据结构。 线段树每个节点代表一个区间。线段树具有唯一根节点&#x…

关于KDDockWidget源码修改和自定义

前言 前面的文章介绍过KDDockWidget的基本使用及示例,文章在这里: KDDockWidgets源码编译及安装 qml dockwidget窗口停靠 QML KDDockWidget 实现 tabwidget效果( 窗口可独立浮动和缩放) 今天主要记录一些在KDDockWidget源码中的…