设计模式十:原型模式

文章目录

      • 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中的属性会有数据的时候,在不同位置使用该对象的时候其内部属性的数据不同时,使用单例是不安全的,这个时候使用原型模式

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

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

相关文章

Vscode+QT+Python

参考链接&#xff1a;VSCodePyQt之Python界面编写_vscode编写图形化界面-CSDN博客 1.安装库 pip install PyQt5 pip install PyQt5-tools pip install qt5_applications 2.在VSCode里下载并安装PYQT Integration 3.配置pyqt integration 4.打开qt designer 在工程文件的空白…

python自动化之pytest框架以及数据驱动(第五天)

1.pytest框架需要遵循的规则 &#xff08;1&#xff09;.py 测试文件必须以test 开头(或者以 test结尾) &#xff08;2&#xff09;测试类必须以Test开头&#xff0c;并且不能有 init 方法 &#xff08;3&#xff09;测试方法必须以test 开头 &#xff08;4&#xff09;断言…

分享个好用的GPT网站

目录 一、背景 二、功能描述 1、写代码 2、联网查询 3、AI绘图 一、背景 我现在的开发工作都依靠ChatGPT&#xff0c;效率提升了好几倍。这样一来&#xff0c;我有更多时间来摸鱼&#xff0c;真是嘎嘎香~ ⭐⭐⭐点击直达 ⭐⭐⭐ 二、功能描述 1、写代码 import java.ut…

机器学习之分类回归模型(决策数、随机森林)

回归分析 回归分析属于监督学习方法的一种&#xff0c;主要用于预测连续型目标变量&#xff0c;可以预测、计算趋势以及确定变量之间的关系等。 Regession Evaluation Metrics 以下是一些最流行的回归评估指标: 平均绝对误差(MAE):目标变量的预测值与实际值之间的平均绝对差…

基于PHP+Amaze+JQuery的学习论坛的设计与实现1.99

摘 要 互联网教育服务是在互联网技术、通信技术、计算机技术不断发展融合的基础之上&#xff0c;人们在对以信息为基础的各种各样应用需求快速增长的激励之下&#xff0c;在现在社会信息化的水平日益提高前提之下&#xff0c;迅速发展起来的一种全新大众服务方式。 笔者拟设计…

前端食堂技术周刊第 115 期:Rolldown 正式开源、马斯克宣布 xAI 本周将开源 Grok、如何使用 Copilot 完成 50% 的日常工作?

美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;手打柠檬茶 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 大家好&#xff0c;我是童欧巴。欢迎来到前端食堂技术周刊&#xff0c;我们先来看…

Docker的安装及镜像加速的配置

文章目录 一.切换到root二.卸载旧版docker三.配置docker的yum库四.安装Docker五.Docker的启动和验证六.配置Docker阿里云镜像加速(全程免费) 该文章文章演示在Linux系统中安装docker&#xff0c;Windows安装docker请参考以下文章 Windows系统中安装docker及镜像加速的配置 一…

基于android的物业管理系统的设计与实现19.8

目录 基于android的物业管理系统的设计与实现 3 摘 要 3 Android property managemengt system 5 Abstract 5 1 绪论 6 1.1 选题背景 6 1.2 课题研究现状 6 1.3 设计研究主要内容 7 1.4 系统主要设计思想 8 2 开发环境 8 2.1 Android系统的结构 8 图2-1 Android系统架构图 9 2…

kibana新增查看更新删除es中的数据

登录kibana&#xff0c;打开开发工具 写入数据 PUT test20240311/person/1 {"name": "张三","mobile":"13011111111" } 查询数据 GET /test20240311/person/_search {"query": {"term": {"mobile": {…

中科数安|公司办公终端、电脑文件数据 \ 资料防泄密系统

#中科数安# 中科数安是一家专注于信息安全技术与产品研发的高新技术企业&#xff0c;其提供的公司办公终端、电脑文件数据及资料防泄密系统&#xff08;也称为终端数据防泄漏系统或简称DLP系统&#xff09;主要服务于企业对内部敏感信息的安全管理需求。 www.weaem.com 该系统…

ffmpeg日记4001-原理介绍-视频切割原理

原理 打开输入---->打开输出---->根据输入来创建流---->拷贝流设置---->循环读帧---->判断时间点是否到达切割点&#xff0c;并做设置---->设置pts和dts---->写入---->善后 重点是pts和dts如何设置。参考《ffmpeg学习日记25-pts&#xff0c;dts概念的…

HBase非关系型数据库

HBase非关系型数据库 1 什么是HBase2 HBase的特点3 什么时候需要HBase4 HBase的数据模型5 HBase架构5.1 架构5.2 HBase如何列式储存 6 如何正确设计RowKey 1 什么是HBase HBase – Hadoop Database&#xff0c;是一个高可靠性、高性能、面向列、可伸缩、 实时读写的分布式数据…

Java并发编程: AQS

文章目录 一、前置知识二、什么是AQS三、使用AQS框架的锁和同步器1、ReentrantLock2、ReentrantReadWriteLock3、CountDownLatch4、CyclicBarrier5、Semaphore&#xff1a;信号量 四、锁和同步器的关系1、锁&#xff1a;面向锁的使用者2、同步器&#xff1a;面向锁的实现者 五、…

Material UI 5 学习03-Text Field文本输入框

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Text Field文本输入框 一、最基本的本文输入框1、基础示例2、一些表单属性3、验证 二、多行文本 一、最基本的本文输入框 1、基础示例 import {Box, TextField} from "…

九、ELMo 语言模型

ELMo&#xff08;Embeddings from Language Models&#xff09;兼顾了两个问题&#xff1a;一是词语用法在语义和语法上的复杂特点&#xff1b;二是随着语言环境的改变&#xff0c;这些用法也应该随之改变&#xff0c;解决多义词的问题。 ELMo 语言模型原理图&#xff1a; ELMo…

Matlab如何批量读取Excel数据?科研效率UpUp第3期

上一篇文章中&#xff0c;讲了如何批量统计一组Excel数据中多个站位所有物种的数量之和&#xff08;Matlab如何高效统计多站数据中各站目标总数&#xff1f;科研效率UpUp第2期&#xff09;。 进一步&#xff0c;假如我们有多组Excel数据&#xff0c;也就是多个Excel表格&#…

【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-先导篇)

专栏系列文章推荐&#xff1a; 2024高级系统架构设计师备考资料&#xff08;高频考点&真题&经验&#xff09;https://blog.csdn.net/seeker1994/category_12601310.html 案例分析篇01&#xff1a;软件架构设计考点架构风格及质量属性&#xff08;2024年软考高级系统…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Navigation)

Navigation组件是路由导航的根视图容器&#xff0c;一般作为Page页面的根容器使用&#xff0c;其内部默认包含了标题栏、内容区和工具栏&#xff0c;其中内容区默认首页显示导航内容&#xff08;Navigation的子组件&#xff09;或非首页显示&#xff08;NavDestination的子组件…

使用 Amazon Bedrock 和 RAG 构建 Text2SQL 行业数据查询助手

背景 随着企业数据量的持续增长&#xff0c;如何让非技术人员也能轻松分析数据、获得商业洞察成为了当前的痛点。本文将介绍如何使用亚马逊云科技的大语言模型服务 Amazon Bedrock 以及 RAG (Retrieval Augmented Generation)&#xff0c;实现 Text2SQL 功能&#xff0c;以此为…

图论(二)之最短路问题

最短路 Dijkstra求最短路 文章目录 最短路Dijkstra求最短路栗题思想题目代码代码如下bellman-ford算法分析只能用bellman-ford来解决的题型题目完整代码 spfa求最短路spfa 算法思路明确一下松弛的概念。spfa算法文字说明&#xff1a;spfa 图解&#xff1a; 题目完整代码总结ti…