单例设计模式(2)

单例设计模式(2)

单例模式存在的问题

单例对 OOP 特性的支持不友好

  • oop的特性:封装、继承、多态、抽象;
  • 以Id生成器代码为例,如果未来某一天,我们希望针对不同的业务采用不同的 ID 生成算法。比如,订单 ID 和用户 ID 采用不同的 ID 生成器来生成。为了应对这个需求变化,我们需要修改所有用到 IdGenerator 类的地方,这样代码的改动就会比较大。
单例会隐藏类之间的依赖关系
  • 通过构造函数、参数传递等方式声明的类之间的依赖关系,我们通过查看函数的定义,就能很容易识别出来。
  • 但是,单例类不需要显示创建、不需要依赖参数传递,在函数中直接调用就可以了。如果代码比较复杂,这种调用关系就会非常隐蔽。在阅读代码的时候,我们就需要仔细查看每个函数的代码实现,才能知道这个类到底依赖了哪些单例类。

单例对代码的扩展性不友好

  • 以数据库连接池为例,数据库连接池是单例的,但是,在一个系统中存在慢sql,这些 SQL 语句在执行的时候,长时间占用数据库连接资源,导致其他 SQL 请求无法响应。我们需要将数据库连接池隔离开,一个是正常的sql执行,一个是慢sql的执行器;
  • 如果设计为单例的模式,印象了扩展性

单例对代码的可测试性不友好

  • 首先,单例模式的硬编码式使用方式使得在编写单元测试时无法轻松地通过 mock 替换依赖的外部资源,比如数据库。、
  • 其次,单例类持有的成员变量相当于全局变量,被所有代码共享,
    如果这些成员变量是可变的,就可能导致不同测试用例之间相互影响的问题,
  • 需要特别注意。这种情况类似于全局变量的使用,容易造成测试结果不确定性和测试用例之间的耦合。

单例不支持有参数的构造函数

  • 数据库连接池的情况下,需要设置数据库连接池的大小、最大的连接数、连接存活时间等
替代方案
  • 引入外部的配置类(可以使用代码的形式、可以采用从配置文件中加载的方式),在单例类初始化时,对单例类的成员变量进行赋值
/*** 配置类,在单例类中使用依赖注入的方式或者其他方式引入*/
class Config {public static int parmaA;public static int parmaB;
}/*** 单例类*/
public class Singleton {private static Singleton instance = null;private final int paramA;private final int paramB;public Singleton() {this.paramA = Config.parmaA;this.paramB = Config.parmaA;}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

替代方案

  • 为了保证全局唯一,除了使用单例,我们还可以用静态方法来实现。这也是项目开发中经常用到的一种实现思路
// 静态方法实现方式
public class IdGenerator {private static AtomicLong id = new 	AtomicLong(0);
public static long getId() {return id.incrementAndGet();}
}
// 使用举例long id = IdGenerator.getId();
  • 使用过程中的方法
    // 1. 老的使用方式public demofunction() {
//...long id = IdGenerator.getInstance().getId();
//...}// 2. 新的使用方式:依赖注入public demofunction(IdGenerator idGenerator) {long id = idGenerator.getId();}// 外部调用demofunction()的时候,传入idGeneratorIdGenerator idGenerator = IdGenerator.getInsance();demofunction(idGenerator);

但是这是解决了决单例隐藏类之间依赖关系,对于其他的问题还是无法解决

  • 我们本质上是实现类的全局唯一性,除了单例模式,我们还可以通过工厂方法,IOC容器等方案来保证

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

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

相关文章

通过多选按钮选择需要修改什么字段

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、代码 前言 想要更新什么字段就将该字段更新,第一想到通过多选框控制,通过一系列的尝试,做了如下的布局和功能 直接上代…

[操作系统课设]GeeKOS操作系统的研究与实现

一.GeekOS操作系统概论 1.1教学操作系统 (1)针对RISC结构MIPS处理器 操作系统:Nachos、OS/161 (2)针对CISC结构Intel IA-32 (or x86)通用处理 操作系统:MINIX、GeekOS 我们用到的是:GeekOS 1&…

二分(二段性)

本文用于记录个人算法竞赛学习,仅供参考 一.二分算法 二分算法一般用于具有二段性的问题,数据不一定具有单调性,所以单调可二分,可二分不一定就要单调。 二.整数二分 1. 模板一:将区间[l, r]划分为[l, mid] 和 [mid…

字符串(KMP)

P3375 【模板】KMP - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; #define ll long long const int N1e6100; int n0,m; char s1[N]; char s2[N];…

36.HarmonyOS鸿蒙系统 App(ArkUI) 创建第一个应用程序hello world

36.HarmonyOS App(ArkUI) 创建第一个应用程序helloworld 线性布局 1.鸿蒙应用程序开发app_hap开发环境搭建 3.DevEco Studio安装鸿蒙手机app本地模拟器 打开DevEco Studio,点击文件-》新建 双击打开index.ets 复制如下代码&#xff1a; import FaultLogger from ohos.fau…

通俗易懂Redis缓存穿透,缓存击穿,缓存雪崩

1.1 缓存穿透 原因&#xff1a;当我们查询一个数据的时候&#xff0c;缓存中没有&#xff0c;就会去查询我们的关系型数据库&#xff0c;而且查询不到的数据是不会放到我们的缓存中&#xff0c;就会导致我们每次的请求都会来到我们的关系型数据库中&#xff0c;从而导致关系型…

代码随想录刷题day39|不同路径不同路径II

文章目录 day39学习内容一、不同路径2.1、动态规划五部曲1.1.1、 确定dp数组&#xff08;dp table&#xff09;以及下标的含义1.1.2、确定递推公式1.1.3、 dp数组如何初始化1.1.4、确定遍历顺序1.1.5、计算并返回最终结果 1.2、代码 二、不同路径II2.1、动态规划五部曲2.1.1、 …

使用Flink实现Kafka到MySQL的数据流转换:一个基于Flink的实践指南

使用Flink实现Kafka到MySQL的数据流转换 在现代数据处理架构中&#xff0c;Kafka和MySQL是两种非常流行的技术。Kafka作为一个高吞吐量的分布式消息系统&#xff0c;常用于构建实时数据流管道。而MySQL则是广泛使用的关系型数据库&#xff0c;适用于存储和查询数据。在某些场景…

小米SU7 我劝你再等等

文 | AUTO芯球 作者 | 李逵 我必须承认我一时没忍住 犯错了 我不会被我老婆打吧 感觉有点慌呀 这不前两天 我刚提了台问界M9嘛 但是昨晚看小米汽车发布会 是真的被雷总感染到了 真的没忍住 我又冲了台小米SU7 Pro版 本来我是准备抢创始版的 结果1秒钟时间 点进去就…

yolov5 v7.0打包exe文件,使用C++调用

cd到yolo5文件夹下 pyinstaller -p 当前路径 -i logo图标 detect.py问题汇总 运行detect.exe找不到default.yaml 这个是yolov8里的文件 1 复制权重文件到exe所在目录。 2 根据报错提示的配置文件路径&#xff0c;把default.yaml复制放到相应的路径下。&#xff08;缺少相应…

杨辉三角形(c++实现)

题目 下面的图形是著名的杨辉三角形&#xff1a; 如果我们按从上到下、从左到右的顺序把所有数排成一列&#xff0c;可以得到如下数列&#xff1a; 1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, … 给定一个正整数 N&#xff0c;请你输出数列中第一次出现 N 是在第几个数&a…

实现 Element UI el-table 树形数据的懒加载

当面对大量数据时&#xff0c;一次性加载所有数据可能会导致性能问题。为了解决这一问题&#xff0c;我们可以实现树形数据的懒加载。本文将介绍如何在使用 Element UI 的 Vue 应用中为 el-table 组件的树形数据添加懒加载功能。 懒加载的基本概念 懒加载是一种优化网页或应用…

中国31个省农村用电量(2000-2022年)

数据介绍&#xff1a; 农村用电量是一个动态变化的数据&#xff0c;受到多种因素的影响&#xff0c;包括农村经济发展、人口增长、农业生产活动增加以及电力设备的升级改造等。随着农村经济的发展和农民生活水平的提高&#xff0c;农村用电量呈现出逐年增长的趋势。同时&#…

收获的果实将远远超出你的想象

在追求目标的过程中&#xff0c;刚开始的时候努力所带来的收获可能显得微不足道。然而&#xff0c;随着时间的推移&#xff0c;你会逐渐发现收获的增长是远远超过最初付出的努力的。这就像种下一颗种子&#xff0c;一开始你可能需要付出很多精力去浇灌它&#xff0c;但随着时间…

消息中间件区别

ActiveMQ 我们先看ActiveMQ。其实一般早些的项目需要引入消息中间件&#xff0c;都是使用的这个MQ&#xff0c;但是现在用的确实不多了&#xff0c;说白了就是有些过时了。我们去它的官网看一看&#xff0c;你会发现官网已经不活跃了&#xff0c;好久才会更新一次。 它的单机吞…

LeetCode 2908.元素和最小的山形三元组 I:贪心(两次遍历)——双O(n)复杂度

【LetMeFly】2908.元素和最小的山形三元组 I&#xff1a;贪心&#xff08;两次遍历&#xff09;——双O(n)复杂度 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-sum-of-mountain-triplets-i/ 给你一个下标从 0 开始的整数数组 nums 。 如果下标三元组 (i,…

查找某数据在单链表中出现的次数

#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> typedef int ElemType; typedef struct LinkNode {ElemType data;LinkNode* next; }LinkNode, * LinkList; //尾插法建立单链表 void creatLinkList(LinkList& L) {L (LinkNode*)mallo…

JAVA反射基础篇

简介 Java反射是指在运行时动态地获取类的信息&#xff0c;并可以通过该信息来操作类或对象。通过反射&#xff0c;我们可以在运行时获取类的字段、方法、构造函数等信息&#xff0c;并能够动态地创建对象、调用方法、访问和修改字段的值。 一丶概念 反射是Java语言的一种机…

2024.2.5力扣每日一题——跳跃游戏6

2024.2.5 题目来源我的题解方法一 深度搜索实现方法二 动态规划双端队列 题目来源 力扣每日一题&#xff1b;题序&#xff1a;1696 我的题解 方法一 深度搜索实现 使用深度搜索&#xff0c;每次选择一个在范围内的跳跃点&#xff0c;但是时间通不过。 时间复杂度&#xff1a…

Kafka配置与部署CentOS7[]

静态IP设置 # 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33# 修改文件内容 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic IPADDR192.168.18.128 NETMASK255.255.255.0 GATEWAY192.168.18.2 DEFROUTEyes IPV4_FAILURE_FATALno IPV6INIT…