设计模式十:原型模式

news2024/10/6 5:54:11

文章目录

      • 1、原型模式
        • 1.1 类创建过程
        • 1.2 浅拷贝
        • 1.3 深拷贝
      • 2、示例
        • 2.1 简单形式
        • 2.2 复杂形式
      • 3、spring中的原型模式
        • 3.1 ArrayList的原型模式
        • 3.2 spring中的原型模式

1、原型模式

原型模式就是从一个对象再创建另外一个可定制的对象, 而且不需要知道任何创建的细节。
所谓原型模式, 就是 Java 中的克隆技术, 以某个对象为原型。 复制出新的对象。 显然新的对象具备原型对象的特点, 效率高(避免了重新执行构造过程步骤)

1.1 类创建过程

回顾一下 new一个对象的流程

10.1、类创建过程

  1. 加载类。虚拟机首先检查参数是否能定位到一个类的符号引用,并确认这个类是否已经被加载、解析和初始化过。如果没有,它会尝试加载这个类,这包括查找类的.class文件,并在加载过程中完成类的验证、准备和解析工作。
  2. 分配内存。虚拟机为对象分配内存。分配内存的方式取决于垃圾收集器使用的算法。如果内存是规整的,使用指针碰撞法,即移动指针来分配内存。如果内存不规整,则使用空闲列表法,即维护一个内存可用列表来分配内存。
  3. 设置对象头。虚拟机会设置对象头信息,包括对象的类元信息、哈希码、GC分代年龄等.
  4. 初始化成员变量。虚拟机会将分配到的内存空间初始化为零值。
  5. 执行构造函数。虚拟机会执行构造函数,根据传入的属性值给对象的属性赋值。
  6. 返回对象引用。在栈中创建一个对象引用,并将其指向堆中新创建的对象实例。

而通过拷贝的方式,没有执行构造函数的步骤(如果对象没有其他类的属性,则也不涉及类加载过程),所以轻量级对象(构造函数里面没有复杂的操作)的创建,new创建会比较快;而如果构造函数中有一些简单的操作,深拷贝完胜new。

原型模式有简单形式(浅拷贝)和复杂形式(深拷贝)

1.2 浅拷贝

浅拷贝仅仅是返回对象的引用,两变量使用同一堆内存中的对象实例

1.3 深拷贝

深拷贝需要实现**Cloneable接口,并重写clone**方法,会分配堆存,并进行数据的拷贝,两个变量指向的是不同的堆内对象实例

注:深拷贝仅对该对象实例进行了拷贝,使得两个变量执行不同的堆内对象实例,但是其内部的引用对象使用的仍是浅拷贝,若需要其饮用对象属性也需要进行深拷贝,则在clone()方法内部进行操作

2、示例

UserService 内部有一个 orderService 引用对象属性,对UserService采用原型模式创建对象

2.1 简单形式
public class OrderService {
    String value = "sxf";
}

public class UserService {
    public OrderService orderService;

    public UserService(OrderService orderService) {
        this.orderService = orderService;
    }

    public void test(){
        System.out.println(orderService);
    }

    public Object clone(){
        return this;
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        OrderService orderService = new OrderService();

        UserService userService1 = new UserService(orderService);
        System.out.println("userService1: " + userService1);
        System.out.println("userService1.orderService: " + userService1.orderService);

        UserService userService2 = (UserService) userService1.clone();
        System.out.println("userService2: " + userService2);
        System.out.println("userService2.orderService: " + userService2.orderService);
    }
}

输出结果:

userService1: com.designPattern.prototype.simple.UserService@c355be
userService1.orderService: com.designPattern.prototype.simple.OrderService@8cf4c6
userService2: com.designPattern.prototype.simple.UserService@c355be
userService2.orderService: com.designPattern.prototype.simple.OrderService@8cf4c6

简单的原型模式,返回的仅是原型对象的引用,当userService2改变时,会相应的改动userService1

2.2 复杂形式
public class OrderService{
    String value = "sxf";
}

//实现Cloneable接口,并重写Object的clone方法
public class UserService implements Cloneable{
    public OrderService orderService;

    public UserService(OrderService orderService) {
        this.orderService = orderService;
    }

    public void test(){
        System.out.println(orderService);
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
//测试类
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        OrderService orderService = new OrderService();

        UserService userService1 = new UserService(orderService);
        System.out.println("userService1: " + userService1);
        System.out.println("userService1.orderService: " + userService1.orderService);

        UserService userService2 = (UserService) userService1.clone();
        System.out.println("userService2: " + userService2);
        System.out.println("userService2.orderService: " + userService2.orderService);
    }
}

输出结果:

userService1: com.designPattern.prototype.complex.UserService@c355be
userService1.orderService: com.designPattern.prototype.complex.OrderService@8cf4c6
userService2: com.designPattern.prototype.complex.UserService@edcd21
userService2.orderService: com.designPattern.prototype.complex.OrderService@8cf4c6

可以发现,该方式会对对象进行深拷贝

但是其内部的引用对象仍然相同,所以深拷贝要考虑深度的问题,比如,我们可以在对orderService进行深拷贝,但是如果orderService中也有引用类型,需不需要在进行深拷贝,这个是要考虑的

对内部的引用类型进行拷贝:

public class OrderService implements Cloneable{
    String value = "sxf";

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

public class UserService implements Cloneable{
    public OrderService orderService;

    public UserService(OrderService orderService) {
        this.orderService = orderService;
    }

    public void test(){
        System.out.println(orderService);
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        UserService userService = (UserService) super.clone();
        userService.orderService = (OrderService) userService.orderService.clone();
        return  userService;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        OrderService orderService = new OrderService();

        UserService userService1 = new UserService(orderService);
        System.out.println("userService1: " + userService1);
        System.out.println("userService1.orderService: " + userService1.orderService);

        UserService userService2 = (UserService) userService1.clone();
        System.out.println("userService2: " + userService2);
        System.out.println("userService2.orderService: " + userService2.orderService);
    }
}

执行结果:

userService1: com.designPattern.prototype.complex.UserService@c355be
userService1.orderService: com.designPattern.prototype.complex.OrderService@8cf4c6
userService2: com.designPattern.prototype.complex.UserService@edcd21
userService2.orderService: com.designPattern.prototype.complex.OrderService@c45dca

3、spring中的原型模式

3.1 ArrayList的原型模式

java中ArrayList重写了clone()方法

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}
public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

虽然其进行了深拷贝,但是仅仅是对基本类型数据的深拷贝,其针对引用类型的数据,仍然是浅拷贝

3.2 spring中的原型模式

我们知道一般spring中的bean都是单例,但是我们可以将bean设置为原型模式(以前傻傻地叫这个为多例模式…)

@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 或者@Scope("prototype")
public class UserService{}

当spring启动后,当需要一个bean的时候,从IOC容器中查找出来,判断是单例还是原型,如果是原型模式,则生成一个对象实例,而不是将IOC容器管理的对象实例返回给用户,创建实例的方式为调用类的构造方法

SpringContextUtil类,方便执行getBean()方法

@Component
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }

    public static Object getBean(Class c) {
        return applicationContext.getBean(c);
    }
}

通过getBean()方法进入到AbstractBeanFactorygetBean()方法,最终执行doGetBean()方法

10.2doGetBean

方法中会判断是否为单例还是原型模式

;

进入到createBean()方法,可以看到doCreateBean()方法

在这里插入图片描述

doCreateBean方法中判断如果是单例,则从缓存中删除;如果是原型,则调用createBeanInstance创建实例

在这里插入图片描述

createBeanInstance方法中最后使用类的构造方法创建了实例

在这里插入图片描述


spring中使用原型模式的场景:

当bean中的属性会有数据的时候,在不同位置使用该对象的时候其内部属性的数据不同时,使用单例是不安全的,这个时候使用原型模式

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

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

相关文章

前端解决跨域问题( 6种方法 )

本专栏是汇集了一些HTML常常被遗忘的知识&#xff0c;这里算是温故而知新&#xff0c;往往这些零碎的知识点&#xff0c;在你开发中能起到炸惊效果。我们每个人都没有过目不忘&#xff0c;过久不忘的本事&#xff0c;就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…

使用JDBC操作数据库

意志、工作和等待是成功的金字塔的基石。 Will, work and wait are the pyramidal cornerstones for success. 文章目录 JDBC简介&#xff1a;JDBC访问数据库步骤StatementPreparedStatement JDBC简介&#xff1a; 在Java应用程序中&#xff0c;JDBC&#xff08;Java Database…

CSS 入门指南(二)CSS 常用样式及注册页面案例

CSS 常用样式 颜色属性 常见样式的颜色属性&#xff1a; color&#xff1a;定义文本的颜色border-color&#xff1a;定义边框的颜色background-color&#xff1a;设置背景色 颜色属性值设置方式&#xff1a; 十六进制值 - 如&#xff1a;&#xff03;FF0000一个RGB值 - 如…

docker安装ollama

拉取镜像 docker pull ollama/ollama 运行容器 &#xff08;挂载路径 D:\ollama 改成你自己喜欢的路径&#xff09; CPU only docker run -d -v D:\ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama Nvidia GPU&#xff08;没试过这个&#xff09; doc…

LeetCode203:移除链表元素

题目描述 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 解题思想 使用虚拟头节点 代码 struct ListNode {int val;ListNode* next;ListNode() :val(0), next(nullptr) {};ListNode(i…

1 Tomcat服务器Servlet入门

今日目标 web知识概述tomcat【重点】创建servlet xml anno&#xff08;注解&#xff09;servlet执行原理servlet生命周期servlet体系结构 1.web相关知识概述【了解】 1.WEB简介 学习目标 了解什么是web 内容讲解 Web&#xff08;World Wide Web&#xff09;即全球广域网…

MyBatisPlus理解

MyBatisPlus是mybatis的增强&#xff0c;mybatis是数据库持久化的框架&#xff0c;但mybatisplus并不是替代mybatis&#xff0c;而是相辅相成的关系 MyBatisPlus不会对以前使用mybatis开发的项目进行影响&#xff0c;引入后仍然正常运行。 使用方法&#xff1a; 1.在引入了对…

IDM的使用详解 IDM是哪个国家的 IDM功能强大的网络下载器 idm下载

对于idm相信大家都不陌生&#xff0c;全称是Internet Download Manager。idm是一款非常经典、功能强大的Windows文件多线程下载加速软件&#xff0c;在电脑用户中口碑极好&#xff0c;被称为必装的HTTP下载神器。那么idm下载器是哪个国家的&#xff0c;idm下载器是哪个公司的呢…

重学SpringBoot3-集成Thymeleaf

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 重学SpringBoot3-集成Thymeleaf 1. 添加Thymeleaf依赖2. 配置Thymeleaf属性&#xff08;可选&#xff09;3. 创建Thymeleaf模板4. 创建一个Controller5. 运行应用并访问页面Thymeleaf基本语法小技巧 国际化步骤 …

【漏洞复现】华三用户自助服务产品dynamiccontent.properties.xhtml接口处存在RCE漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

【python 】----Pytest基础知识与进阶知识

定义 用于编写和执行Python测试全功能测试框架(工具),是一个第三方库 安装 pip insatll pytest 安装pytest --version 校验 pytest的组成构成 不写调用语句也可以执行函数内容 在用例运行语句里面: -s:指的是开启与终端的交互,如果没有-s(程序不会输入与打印),一条用…

Tiktok/抖音旋转验证码识别方案

一、引言 在数字世界的飞速发展中&#xff0c;安全防护成为了一个不容忽视的课题。Tiktok/抖音&#xff0c;作为全球最大的短视频平台之一&#xff0c;每天都有数以亿计的用户活跃在其平台上。为了保护用户的账号安全&#xff0c;Tiktok/抖音引入了一种名为“旋转验证码”的安…

[数据结构]OJ用队列实现栈

225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; 官方题解&#xff1a;https://leetcode.cn/problems/implement-stack-using-queues/solutions/432204/yong-dui-lie-shi-xian-zhan-by-leetcode-solution/ 首先我们要知道 栈是一种后进先出的数据结构&#xff0c…

[Spring] IoC 控制反转和DI依赖注入和Spring中的实现以及常见面试题

目录 1. 什么是Spring 2.什么是IoC容器 3.通过实例来深入了解IoC容器的作用 3.1造一量可以定义车辆轮胎尺寸的车出现的问题 3.2解决方法 3.3IoC优势 4.DI介绍 5.Spring中的IoC和DI的实现 5.1.存对象 5.1.2 类注解 5.1.3 方法注解 5.2取对像 (依赖注入) 5.2.1.属性…

esp32 idf.py cmd powershell 环境

esp32 idf.py cmd powershell 命令行 环境 win10 推荐使用 Windows Terminal 替换自己路径 设置–>添加新配置文件–>选择cmd 或者 powershell -->保存–> 去修改命令行 启动目录&#xff0c;推荐使用父进程目录 powershell C:\WINDOWS/System32/WindowsPowe…

Docker 容器化技术:构建高效、可移植的开发环境和部署流程|Docker 概述

容器技术是云原生的核心技术之一&#xff0c;利用容器化技术&#xff0c;可以将微服务以及它所需要的配置、依赖关系、环境变了等都可以便捷地部署到新的服务器节点上&#xff0c;而不用再次重新配置&#xff0c;这就使得微服务具备了强大的可移植性。 一、Docker 概述 Docke…

【前端系列】CSS 常见的选择器

CSS 常见的选择器 CSS&#xff08;层叠样式表&#xff09;是一种用于描述网页样式的标记语言&#xff0c;它定义了网页中各个元素的外观和布局。在 CSS 中&#xff0c;选择器是一种用于选择要应用样式的 HTML 元素的模式。选择器允许开发人员根据元素的类型、属性、关系等来选…

Android平台实现无纸化同屏并推送RTMP或轻量级RTSP服务(毫秒级延迟)

技术背景 在写这篇文章之前&#xff0c;实际上几年之前&#xff0c;我们就有非常稳定的无纸化同屏的模块&#xff0c;本文借demo更新&#xff0c;算是做个新的总结&#xff0c;废话不多说&#xff0c;先看图&#xff0c;本文以Android平台屏幕实时采集推送&#xff0c;Windows…

javaEE6(网站第3章-jsp练习中三个例题动手做一遍;课后题2(1),(2))

两个数求和 用javascript实现。 输入、处理、输出用同一个页面(自己处理自己)。 输入1.jsp&#xff0c;处理和输出2.jsp。 &#xff08;4&#xff09;输入1.jsp&#xff0c;处理2.jsp&#xff0c;处理完转回1.jsp显示结果。 &#xff08;5&#xff09;输入1.jsp&#xff0c;处…

【Prometheus】k8s集群部署node-exporter

​ 目录 一、概述 1.1 prometheus简介 1.2 prometheus架构图 1.3 Exporter介绍 1.4 监控指标 1.5 参数定义 1.6 默认启用的参数 1.7 prometheus如何收集k8s/服务的–三种方式收集 二、安装node-exporter组件 【Prometheus】概念和工作原理介绍-CSDN博客 【云原生】ku…