设计模式-多例模式

设计模式专栏

    • 模式介绍
    • 多例模式和单例模式的区别
    • 应用场景
    • Spring中多例模式的优缺点
    • 代码示例
      • Java实现多例模式
      • Python实现多例模式
    • 多例模式在spring中的应用


模式介绍

多例模式是一种创建型设计模式,属于对象创建类型。多例模式的特点是允许一个类有多个实例,并且这些实例都是该类本身。多例模式通常用于设计复杂的系统,例如数据库连接、网络通信等。

多例模式的优点包括:

  1. 可以限制实例数量:多例模式可以限制实例数量,确保系统中只有指定数量的实例存在,避免过多的资源消耗。
  2. 可以复用已有实例:多例模式可以复用已有实例,避免重复创建对象,提高系统性能。
  3. 可以灵活控制实例的生命周期:多例模式可以灵活控制实例的生命周期,可以在需要时创建实例,也可以在不需要时销毁实例,避免浪费系统资源。

多例模式的缺点包括:

  1. 难以扩展:多例模式的实例数量是固定的,难以动态地增加或减少实例数量。
  2. 难以测试:由于多例模式的实例数量是固定的,难以对每个实例进行单独的测试。
  3. 破坏封装性:多例模式需要全局访问实例,这破坏了封装性,使得代码难以维护和扩展。
  4. 代码复杂度高:多例模式的实现需要考虑线程安全、序列化等问题,因此代码复杂度较高。

多例模式可以通过实现一个内部类来管理实例的创建和销毁,这个内部类通常被称为“工厂”或“容器”。多例模式有多种实现方式,包括有上限多例模式和无上限多例模式等。在实际应用中,需要根据具体需求选择适合的实现方式。

在这里插入图片描述

多例模式和单例模式的区别

多例模式和单例模式都属于对象创建类型的模式,但它们在实现和应用上有明显的区别。

首先,单例模式要求一个类只有一个实例,并提供一个全局访问点。这意味着无论在程序中的哪个位置访问该类,都将获得同一个实例。单例模式通常用于需要频繁创建和销毁对象的场景,如线程池、缓存等。单例模式的优点包括提供对唯一实例的受控访问、节约系统资源、提高性能等。缺点是扩展困难、职责过重等。

多例模式则允许一个类有多个实例。多例模式的实现通常需要借助静态工厂方法来向外界提供循环使用的实例。多例模式的应用场景包括管理可重复使用的资源,如数据库连接池、线程池等。多例模式的优点是可以复用已有实例、避免重复创建对象、提高系统性能和资源利用率等。缺点是难以扩展、难以测试、破坏封装性、代码复杂度高。

综上所述,多例模式和单例模式在实现和应用上有明显的区别。单例模式强调唯一性,适用于需要频繁创建和销毁对象的场景;而多例模式则允许有多个实例,适用于管理可重复使用的资源。在实际应用中,需要根据具体需求选择适合的模式。

在这里插入图片描述

应用场景

多例模式是一种创建型设计模式,其应用场景主要在于管理可重复使用的资源,如线程池、数据库连接池等。这些场景中,多例模式能够复用已有实例,避免重复创建对象,从而提高系统性能并避免浪费系统资源。

具体来说,多例模式的应用场景包括:

  1. 数据库连接 :在数据库应用中,通常需要为每个客户端请求创建一个数据库连接。然而,创建新的数据库连接是一项开销较大的操作,而且如果每个请求都创建新的连接,会很快耗尽系统的资源。因此,我们通常会使用多例模式来管理数据库连接。创建一个数据库连接池,该连接池可以预先创建一定数量的数据库连接,并保存在连接池中。当有新的请求需要连接数据库时,系统会先从连接池中获取一个空闲的连接,如果连接池中没有空闲的连接,则等待一段时间或者创建新的连接。当请求结束后,该连接会被放回连接池中,以供其他请求使用。通过这种方式,我们可以重复利用已有的连接,避免频繁创建和销毁连接,提高了系统的性能和稳定性。
  2. EJB无状态会话Bean的实例池 :EJB无状态会话Bean是一种特殊的会话Bean,它不保存客户端的状态。由于无状态会话Bean不需要保存客户端的状态,因此可以重复使用同一个实例来处理多个客户端请求。为了实现这个目标,我们可以使用多例模式来管理无状态会话Bean的实例。创建一个实例池,该池中包含了多个无状态会话Bean的实例。当客户端请求到来时,从实例池中获取一个空闲的实例,处理请求后将该实例放回实例池中,以供其他请求使用。通过这种方式,我们可以复用无状态会话Bean的实例,提高系统的性能和并发处理能力。

总的来说,多例模式的应用场景主要涉及可重复使用的资源管理,通过复用已有实例来提高系统性能和资源利用率。在实际应用中,需要根据具体需求选择适合的实现方式。

在这里插入图片描述

Spring中多例模式的优缺点

在Spring框架中,多例模式(prototype scope)是一种常用的依赖注入模式。以下是多例模式的优缺点:

优点:

  1. 性能更好:每次请求都会创建一个新的Bean实例,避免了单例模式中可能存在的线程安全问题,也避免了共享资源带来的开销。
  2. 降低了耦合度:由于每次请求都有独立的实例,因此降低了Bean之间的耦合度。
  3. 支持原型作用域的Bean的生命周期:在Spring中,使用原型作用域的Bean会在每次请求时重新创建,这使得我们可以利用Spring的AOP(面向切面编程)功能来对Bean进行各种增强操作,例如事务管理、日志记录等。

缺点:

  1. 资源消耗较多:由于每次请求都需要创建一个新的Bean实例,因此如果Bean的创建和销毁开销较大,或者应用的请求量非常大,那么可能会导致资源消耗过多。
  2. 不适合需要跨请求保持状态的Bean:由于多例模式为每个请求创建一个新的实例,因此如果Bean需要在跨请求之间保持状态,那么使用多例模式就不合适了。

多例模式适用于那些需要独立实例的Bean,尤其是那些创建和销毁开销较小、状态不需要跨请求保持的Bean。在选择使用单例模式还是多例模式时,需要根据具体的应用场景和需求来决定。

在这里插入图片描述

代码示例

Java实现多例模式

Java实现多例模式可以使用以下步骤:

  1. 创建一个类,该类将包含一个静态的内部类,用于管理实例的创建和销毁。
  2. 在静态内部类中,使用一个静态的Map来保存实例。Map的键是类名,值是该类的实例。
  3. 在静态内部类中,提供一个静态的工厂方法,用于创建实例。该方法首先检查Map中是否已经存在该类的实例,如果存在则直接返回该实例,否则创建一个新的实例并将其保存到Map中。
  4. 在静态内部类中,提供一个静态的销毁方法,用于销毁实例。该方法从Map中移除该类的实例。
  5. 在外部类中,提供一个公共的静态变量,用于访问内部类的实例。

以下是一个示例代码:

public class MultiInstanceExample {private static class InstanceContainer {private static final Map<String, MultiInstanceExample> instances = new HashMap<>();private static final AtomicInteger counter = new AtomicInteger();public static MultiInstanceExample getInstance() {String className = MultiInstanceExample.class.getName();MultiInstanceExample instance = instances.get(className);if (instance == null) {instance = new MultiInstanceExample();instances.put(className, instance);}return instance;}public static void destroyInstance(MultiInstanceExample instance) {String className = instance.getClass().getName();instances.remove(className);}}private MultiInstanceExample() {}public static MultiInstanceExample getInstance() {return InstanceContainer.getInstance();}public static void destroyInstance(MultiInstanceExample instance) {InstanceContainer.destroyInstance(instance);}
}

在上面的代码中,MultiInstanceExample类是一个多例模式的实现。InstanceContainer是一个静态内部类,用于管理实例的创建和销毁。getInstance()方法返回当前类的唯一实例,如果该实例不存在则创建它。destroyInstance()方法从Map中移除该实例。最后,通过调用MultiInstanceExample.getInstance()来获取当前类的唯一实例。

Python实现多例模式

Python实现多例模式可以使用装饰器或者元类的方式。

以下是使用装饰器实现多例模式的示例代码:

def multi_instance(cls):instances = {}def get_instance(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return get_instance@multi_instance
class MyClass:def __init__(self, name):self.name = namedef say_hello(self):print(f"Hello, {self.name}!")

在上面的代码中,multi_instance是一个装饰器函数,它接受一个类作为参数,并返回一个获取类实例的函数。在这个函数中,我们使用一个字典instances来保存类的实例。当获取实例时,我们首先检查该实例是否已经在instances中,如果是则直接返回,否则创建一个新的实例并将其保存到instances中。

接下来,我们使用@multi_instance装饰器来修饰MyClass类。这样,每次调用MyClass()时,都会返回同一个实例。

以下是使用元类实现多例模式的示例代码:

class MultiInstanceMeta(type):_instances = {}def __call__(cls, *args, **kwargs):if cls not in cls._instances:cls._instances[cls] = super().__call__(*args, **kwargs)return cls._instances[cls]class MyClass(metaclass=MultiInstanceMeta):def __init__(self, name):self.name = namedef say_hello(self):print(f"Hello, {self.name}!")

在上面的代码中,我们定义了一个元类MultiInstanceMeta,它继承自type类。在元类的__call__方法中,我们同样使用一个字典_instances来保存类的实例。当调用类时,我们首先检查该实例是否已经在_instances中,如果是则直接返回,否则创建一个新的实例并将其保存到_instances中。最后,我们在MyClass类的定义中指定了元类为MultiInstanceMeta。这样,每次调用MyClass()时,都会返回同一个实例。

在这里插入图片描述

多例模式在spring中的应用

在Spring框架中,多例模式(prototype scope)是一种常用的依赖注入模式。与单例模式(singleton scope)不同,多例模式为每个请求创建一个新的Bean实例。

在Spring中,可以通过在Bean上使用@Scope("prototype")注解或者在XML配置文件中设置prototype作用域来实现多例模式。

多例模式适用于那些需要独立实例的Bean,例如:

  1. 每次请求都需要一个新的实例。
  2. Bean的状态不需要跨请求保持。
  3. Bean的创建和销毁开销较小。

多例模式可以提高应用的性能和资源利用率,因为它可以避免对单例的过度依赖和线程安全问题。但是,如果Bean的创建和销毁开销较大,或者Bean的状态需要在跨请求之间保持,那么使用单例模式可能更为合适。

在这里插入图片描述

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

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

相关文章

西北大学844计算机类考研-25级初试高分总攻略

西北大学844计算机类考研-25级初试高分攻略 个人介绍 ​ 本人是西北大学22级软件工程研究生&#xff0c;考研专业课129分&#xff0c;过去一年里在各大辅导机构任职&#xff0c;辅导考研学生专业课844&#xff0c;辅导总时长达400小时&#xff0c;辅导学生超过20余人&#xf…

Android集成OpenSSL实现加解密-集成

导入so 将编译生成的 OpenSSL 动态库文件&#xff08;.so 文件&#xff09;复制到你的 Android 项目的 libs 目录中 导入头文件 将编译生成的include文件夹导入到项目中 build.gradle添加配置 defaultConfig {……testInstrumentationRunner "androidx.test.runner…

java对象整理

1.对象的创建过程 首先class文件加载到内存中 这个过程如下 “加载”是“类加载”(Class Loading)过程的第一步。这个加载过程主要就是靠类加载器实现的&#xff0c; 包括用户自定义类加载器。 加载到内存后做的事情 申请对象内存 成员变量赋默认值 调用构造方法 成员变量顺序…

前端实现断点续传文件

公司要求实现的功能&#xff0c;大概思路是将上传的文件通过jsZip压缩后&#xff0c;进行切片&#xff0c;留一下总切片&#xff0c;当前片&#xff0c;并把这些数据给后端&#xff0c;至于前端的校验&#xff0c;是由Md5完成的&#xff0c;验证文件唯一性&#xff0c;这样下次…

什么是受检异常和非受检异常 一、首先是异常的本质 二、然后是对受检异常和非受检异常的定义 三、最后我还可以说下他们优点和缺点) 受检异常优点有两个:

文章目录 什么是受检异常和非受检异常一、首先是异常的本质二、然后是对受检异常和非受检异常的定义三、最后我还可以说下他们优点和缺点&#xff09; 受检异常优点有两个&#xff1a; 什么是受检异常和非受检异常 可以从三个方面回答这个问题一、首先是异常的本质&#xff09…

V-rep(CoppeliaSim)添加相机,与python联合仿真,并使用python读取V-rep中的RGB图与深度图

目录 前言在V-rep中构建场景建立python与V-rep通信 前言 本文主要介绍了如何使用python与V-rep联合仿真&#xff0c;并用OpenCV可视化V-rep中视觉传感器所能看到的 RGB图和深度图&#xff0c;效果图如下。 在V-rep中构建场景 本文使用的V-rep版本是3.5&#xff1a; 打开V-…

react使用useState更新数组失败

失败案例&#xff1a; const [addBox, setAddBox] useState([])const itemAdd (item) >{addBox.push(item);setAddBox(addBox)console.log(addBox,点击添加按钮)} 原因&#xff1a;react的useState hook监听的是浅监听 在 React 中&#xff0c;使用 useState Hook 来更新…

junit.Test 的使用方法

在 Maven 项目中使用 JUnit&#xff0c;你需要在项目的 pom.xml 文件中添加 JUnit 依赖。然后&#xff0c;你可以创建测试类&#xff0c;并在测试类中使用 Test 注解标识测试方法。 文章目录 基本使用其他注解Before 和 AfterBeforeClass 和 AfterClassIgnoreRunWith参数化测试…

C#判断骨龄与生活年龄的比较

什么是骨龄 骨龄是骨骼年龄的简称&#xff0c;它能体现人体生长发育程度。随着生长发育&#xff0c;不同年龄段的骨骺发育成熟度不一样而出现不同的影像特征&#xff0c;是骨龄检测的理论基础。手指腕掌具有20多块骨骼&#xff0c;在各个年龄段具有不同的特点&#xff0c;因而…

009:vue结合el-table实现表格行拖拽排序(基于sortablejs)

文章目录 1. 实现效果2. 安装 sortablejs 插件3. 完整组件代码4. 注意点 1. 实现效果 2. 安装 sortablejs 插件 sortablejs 更多用法 cnpm i --save sortablejs3. 完整组件代码 <template><div class"home"><div class"body"><el-ta…

MongoDB 面试题

MongoDB 面试题 1. 什么是MongoDB&#xff1f; MongoDB是一种非关系型数据库&#xff0c;被广泛用于大型数据存储和分布式系统的构建。MongoDB支持的数据模型比传统的关系型数据库更加灵活&#xff0c;支持动态查询和索引&#xff0c;也支持BSON格式的数据存储&#xff0c;这…

catboost回归自动调参

import os import time import optuna import pandas as pd from catboost import CatBoostRegressor from sklearn.metrics import r2_score, mean_squared_error from sklearn.model_selection import train_test_split X_train data.drop([‘label’, ‘b1’, ‘b2’], a…

探究公有云中的巨人:深入分析大数据产品的架构设计

目录 一、服务器分类 二、公有云基础和产品 网络 vpc专有网络 弹性公网IP(Elastic IP)

3种事件绑定的异同(js的问题)

html事件 dom0事件 dom2事件 • 广义javascript ECMAScript DOM BOM DOM0 DOM1 DOM2 • 狭义javascript ECMAScript ES6 ES5 ES3 事件监听的优点&#xff1a;可以绑定多个事件&#xff0c;常规的事件绑定只执行最后绑定的事件 事件绑定&#xff1a;相当于存储…

从外网访问内网服务器:安装到使用一站通

如果你所在的是一个小的实验室&#xff0c;可能并没有大型的服务器集群而是仅是配备了小型服务器&#xff0c;日常工作便是在在局域网内访问服务器进行各项数据处理。因为在外网无法访问内网服务器&#xff0c;极大的限制了我们偶尔在外想监测一下数据的欲望。本文介绍了一种简…

策略模式(及案例)

策略模式 1.策略接口 定义一组算法或操作的通用接口&#xff0c;通常是一个抽象类或接口。该接口声明了策略类所必须实现的方法。 示例&#xff1a; class Strategy {doOperation() {} }2.具体策略 实现策略接口&#xff0c;提供具体的算法实现。每个具体策略类负责处理一…

二、C#基础语法( 函数与方法)

在C#语言中&#xff0c;函数和方法都是用于实现特定功能的代码块。虽然它们有一些相似之处&#xff0c;但它们在使用和定义上有一些细微的差别。 函数&#xff08;Functions&#xff09; 函数在C#中是独立的功能单元&#xff0c;执行特定操作并返回一个值。函数的定义以关键字…

postman win7 低版本 postman7.0.9win64 postman7.0.9win32

百度网盘&#xff1a; postman7.0.9win64&#xff1a; 链接: https://pan.baidu.com/s/18ck9tI0r9Pqoz36MOwwnnQ 提取码: rkf7 postman7.0.9win32&#xff1a; 链接: https://pan.baidu.com/s/1HrpGPrgvVzyAcjdHuwVOpA 提取码: ke5k win7系统安装postman&#xff0c;可能会…

postman使用-04响应

文章目录 响应响应界面说明Pretty&#xff1a;格式化显示&#xff0c;以便查看Raw&#xff1a;不进行任何处理&#xff0c;显示响应数据的原始格式Preview&#xff1a;预览响应体&#xff0c;会自动换行&#xff0c;不会格式化&#xff08;有时候是数据&#xff0c;有时候是页面…

leetcode151. 反转字符串中的单词

题目描述 给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意&#xff1a;输入字符串 s中可能会存在前导…