设计模式-多例模式

news2024/11/27 22:27:39
设计模式专栏

    • 模式介绍
    • 多例模式和单例模式的区别
    • 应用场景
    • 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 = name
    
    def 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 = name
    
    def 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.coloradmin.cn/o/1341664.html

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

相关文章

在Adobe Acrobat上如何做PDF文档签名

Adobe Acrobat如何做PDF文档签名&#xff1f;PDF文档签名是指对PDF文档进行基于证书的数字签名&#xff0c;类似于传统的手写签名&#xff0c;可标识签名文档的人员。与手写签名不同&#xff0c;数字签名难以伪造&#xff0c;因为其包含签名者唯一的加密信息。为PDF文档进行基于…

【计算机视觉】角点检测(Harris、SIFT)

Harris 角点指的是窗口延任意方向移动&#xff0c;都有很大变化量的点。 用数学公式表示为&#xff1a; E(u,v)反映的移动后窗口的差异&#xff0c;w(x,y)为每个像素的点权值&#xff0c;I(xu,yv)是移动的像素值&#xff0c;I(x,y)是移动前的像素值。 将E(u,v)进行泰勒展开&am…

MVC : python实现

不得不承认python是一门强大的语言&#xff0c;也因此才能hold得住人工智能的逻辑实现 MVC的妙处&#xff1a;只要Model的数据结构内容和结构明确&#xff0c;Controller对抽象的View即前面明确的Model的控制逻辑是几乎不怎么改动的&#xff0c;那么。 1、任意替换View的功能已…

MetalLB:本地Kubernetes集群的LoadBalancer负载均衡利器

背景 在本地集群进行测试时&#xff0c;我们常常面临一个棘手的问题&#xff1a;Service Type不支持LoadBalancer&#xff0c;而我们只能选择使用NodePort作为替代。这种情况下&#xff0c;我们通常会配置Service为NodePort&#xff0c;并使用externalIPs将流量导入Kubernetes…

Flink实时电商数仓之DWS层

需求分析 关键词 统计关键词出现的频率 IK分词 进行分词需要引入IK分词器&#xff0c;使用它时需要引入相关的依赖。它能够将搜索的关键字按照日常的使用习惯进行拆分。比如将苹果iphone 手机&#xff0c;拆分为苹果&#xff0c;iphone, 手机。 <dependency><grou…

关于java选择结构switch及反编译

关于java选择结构switch及反编译 在上一篇文章中&#xff0c;我们了解了选择结构中的if else等&#xff0c;本章内容让我们说明一下上一篇文章中的伏笔&#xff0c;switch选择结构&#x1f914; switch多选择结构 多选择结构&#xff1a;多选择结构除了else if &#xff0c;…

Github 2023-12-29 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-29统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Java项目2HTML项目2TypeScript项目2Python项目2非开发语言项目2C项目1JavaScript项目1 精选面试问题列表 创…

Xamarin开发:商场促销(策略设计模式)

Xamarin开发:商场促销&#xff08;策略设计模式&#xff09; 一、介绍二、需求分析三、实现四、需求分析问题1解决方案问题2解决方案 五、增加新需求六、代码优化与分析总结 一、介绍 本文引用《大话设计模式》第二章节的内容进行学习分析&#xff0c;仅供学习使用 这里接着我…

centos7.9 TCP 加速

BBR是谷歌开发的新的TCP加速算法&#xff0c;在网络状况不好的服务器上开启TCP的bbr&#xff0c;可以在无需增加任何硬件投入的情况下实现网络加速&#xff0c;并且客户端无需做任何配置&#xff0c;因此使用起来非常的方便。TCP加速对网络状况较好的内网环境&#xff0c;或者大…

【数据结构和算法】找出两数组的不同

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 哈希类算法题注意事项 2.2 方法一&#xff1a;哈希法 三、代码 3.1 方法一&#xff1a;哈希法 四…

Oracle(4)

子查询 子查询语法很简单&#xff0c;就是select 语句的嵌套使用。 查询工资比SCOTT高的员工信息 分析&#xff1a;两步即可完成 1. 查出SCOTT的工资 SQL> select ename, sal from emp where enameSCOTT 其工资3000 2. 查询比3000高的员工 SQL> select * from emp…

【零基础入门VUE】VueJS - 环境设置

✍面向读者&#xff1a;所有人 ✍所属专栏&#xff1a;零基础入门VUE专栏https://blog.csdn.net/arthas777/category_12537076.html 直接在 HTML 文件中使用 <script> 标签 <html><head><script type "text/javascript" src "vue.min.j…

Spark 集群搭建

文章目录 搭建前准备安装搭建解压并重命名环境变量配置配置文件yarn-site.xmlspark-env.sh 官网求 π(PI) 案例启动spark-shell通过浏览器查看显示查看 Spark 的网页信息展示 搭建前准备 下载地址&#xff1a;Index of /dist/spark (apache.org) 配置好 hadoop 环境&#xff…

实战 | 使用OpenCV快速去除文档中的表格线条(步骤 + 源码)

导 读 本文主要介绍如何使用OpenCV快速去除文档中的表格线条,并给详细步骤和代码。 背景介绍 测试图如下,目标是去除下面三张图中的表格线条,方便后续图像处理。 实现步骤 下面演示详细步骤,以图1为例: 【1】获取二值图像:加载图像、转为灰度图、OTSU二值化 i…

Awesome Chrome Form UI - 框架设计与基础实现

Money is not evil by itself. Its just paper with perceived value to obtain other things we value in other ways. If not money what is evil you may ask? Evil is the unquenchable, obsessive and moral bending desire for more. Evil is the bottomless,soulless …

多模态大模型-CogVLm 论文阅读笔记

多模态大模型-CogVLm 论文阅读笔记 COGVLM: VISUAL EXPERT FOR LARGE LANGUAGEMODELS 论文地址 :https://arxiv.org/pdf/2311.03079.pdfcode地址 : https://github.com/THUDM/CogVLM时间 : 2023-11机构 : zhipuai,tsinghua关键词: visual language model效果:&#xff08;2023…

C++面向对象(OOP)编程-C++11新特性详解

C11作为一个重要的版本&#xff0c;引入了很多新的特性&#xff0c;解决了C语言本身很多遗留的内存泄露问题&#xff0c;并且提供了很多比较灵活的用法。引入的auto&#xff0c;智能指针、线程机制都使得C语言的灵活性、安全性、并发性有了很大的提升。 本文会比较详细的介绍C1…

医疗行业的信息安全现状

文章目录 前言一、医疗行业相关政策法规二、“互联网+医疗健康”推进信息安全建设三、医疗行业网络安全形势依然严峻1、等级保护工作未全面开展落实2、医疗行业网络安全风险较高医疗行业网络安全隐患普遍存在遭受勒索病毒攻击严重3、安全防护水平相对落后缺乏必要的网络安全防护…

QT应用篇 三、QML自定义显示SpinBox的加减按键图片及显示值效果

QT应用篇 一、QT上位机串口编程 二、QML用Image组件实现Progress Bar 的效果 三、QML自定义显示SpinBox的加减按键图片及显示值效果 文章目录 QT应用篇前言一、qml需求二、使用组件1.SpinBox组件2.SpinBox中QML的使用 总结 前言 记录自己学习QML的一些小技巧方便日后查找 QT的…

rsync备份工具

有了同步源服务器之后&#xff0c;就可以使用rsync工具来执行远程同步了&#xff0c;本节介绍的备份操作均在客 户机&#xff08;发起端&#xff09;执行&#xff0c;实际上&#xff0c;同步源与发起端可以是同一台主机&#xff08;当然这种情况不常见&#xff09;&#xff0c;…