当前位置: 首页 > news >正文

C#上位机中的单例应用思考

文章目录

  • 一、前言
  • 二、上位机单例应用场景
    • 2.1 上位机
    • 2.2 单例及其应用
    • 2.3 上位机中的应用
      • 2.3.1 用户登录信息
      • 2.3.2 配置文件
      • 2.3.3 数据连接池
    • 2.4 一个应用场景的思考
  • 三、总结


一、前言

之前写过一篇关于单例的文——C#中单例模式的实现,讲了讲单例是什么以及在C#中的常见代码实现,那篇文的内容偏理论,并不实用。

最近在用WPF写上位机,发现我在实际开发中使用单例时,并不关心其底层实现,也不太会出现这样的单例类代码:

using System;public sealed class Singleton
{private static volatile Singleton instance;private static object syncRoot = new Object();private Singleton() {}public static Singleton Instance{get {if (instance == null) {lock (syncRoot) {if (instance == null) instance = new Singleton();}}return instance;}}
}

而往往是创建一个服务容器(ServiceProvider),然后把想要实现单例的类以单例模式加入其中,并将服务容器公开(通常是放在App类中)以使整个程序代码都能访问之,在想要用到该单例时,从容器中取出即可:

public IServiceProvider Services { get; }private static IServiceProvider ConfigureServices()
{var services = new ServiceCollection();services.AddSingleton<Class>();...return services.BuildServiceProvider();
}

如果你还没有用过这种容器的方式,可能会觉得很麻烦;而一旦接受了这种方式,你会发现它变成了一种定式。几乎所有应用程序都可以这么做(服务容器的这种方式本身也是一种设计模式Ioc)。

这些内容不是本文要讲的东西,本文主要想讲讲上位机程序中单例的应用,以及一个场景该怎样使用单例的思考。


二、上位机单例应用场景

2.1 上位机

先提一下上位机,
上位机通常不是什么庞大的程序,它主要用以:

  • 提供界面,用户可友好操作;
  • 与下位机通讯,将采集的数据加工,并呈现在界面上;
  • 将部分数据存储至数据库,以供报表、查询、统计分析;
  • 与更上层的系统(MES、ERP等)进行对接;
  • 可能还会结合一些专业技术(如视觉、文档处理等)辅助生产。

这样一个体量不大的用于专门设备的程序,其涉及的技术还是挺广的。

2.2 单例及其应用

单例的目的是为了保证一个类在程序中只有一个实例,并提供一个访问它的全局访问点。
很明显,单例这样的设计使一个类只有一个实例,并且要易于外界访问,从而方便对实例进行控制并节约系统资源。

因此,它的应用场景通常为:

  • 有频繁实例化(也就是频繁new)然后销毁的情况;
  • 创建对象耗时过多或者耗资源过多的情况;
  • 频繁访问IO资源的对象,如数据库连接池或文件。

我相信很多人第一次使用单例并不是因为性能的问题,而仅仅想要一个类似于C语言中全局变量的东西,希望有一个类的实例能被不同页面的代码访问到。这其实就是单例中提到的提供全局访问点的特性。

这边有一个大家非常熟悉的应用——Windows上的任务管理器。ctrl + shift + esc打开,并且无论你按多少次,都只会出现一个任务管理器。也就是说,在Windows系统这个程序中,任务管理器是唯一的。

那为什么这样设计,不这样设计会怎样呢?

  1. 如果弹出了多个任务管理器窗口,且这些窗口展示的内容完全一致,这样打开的就全是重复的对象了,就会造成系统资源的浪费,内存的损耗。实际使用中根本不需要多个呈现相同内容的窗口。
  2. 如果弹出了多个任务管理器窗口,且内容不一致,那就更糟糕了。这意味着,某一时刻应用的使用情况和进程、服务等信息存在多个状态,那到底哪个才是真实的呢?显然这更不可取。

由此可见,确保任务管理器在系统中有且仅有一个非常重要。

2.3 上位机中的应用

在上位机的开发中,也会经常遇到类似情况。下面举几个常见的例子:

2.3.1 用户登录信息

上位机有时需要权限功能,某些页面功能需要特定权限才能操作。
也就是在不同页面上,获取到的用户信息是一致的。要实现这个需求,用户信息就要全局唯一。往往是在用户登录时,将包含各种权限的用户信息加载到单例中。

2.3.2 配置文件

上位机程序中经常需要一些参数配置文件,比如设备相关的、用户习惯相关的。如果不使用单例,每次都要new对象,重新读一遍配置文件,很影响性能。如果使用单例,只需要开始时读一遍就好。

2.3.3 数据连接池

为什么要做池化?
因为新建连接很耗时,如果每次新的任务来了,都新建连接,那严重影响性能。所以一般做法是在一个应用中维护一个连接池,这样当任务来时,若有空闲连接,可以直接使用,省去了初始化的开销。

注意:
这里说的单例是对池做单例,而不是对单个数据库连接做单例。
如果是把一个数据库连接对象封存在单例对象中,这样是错误的。如果对单个数据库连接做单例,那多方请求连接时,就只能用一个数据库连接,那不是死的很惨?

2.4 一个应用场景的思考

除了以上的常规使用,我还尝试在页面切换时保留状态的需求上使用单例。
具体场景是这样的,在一个MVVM模式的上位机中有多个页面,我希望切换页面后再切回原页面(页面即Page,可以看成View),其呈现内容仍是之前的。页面的内容可以理解为ViewModel中的属性、命令等。

针对该需求,可以有多种方式使用单例,

  1. 将ViewModel中的部分关键对象单例化(通常是ViewModel中聚合的Model);
  2. 将ViewModel单例化,使程序中仅有一份ViewModel;
  3. 将整个View单例化。

方式1

若将ViewModel中的关键对象单例化,切换回原页面时就重新创建ViewModel,并在其中加载这些单例对象。

方式2

若将整个ViewModel单例化,仅需将View的DataContext绑定到单例ViewModel即可。

方式3

若将整个View单例化,切换页面只需要导航到目标单例View即可。

那么问题来了,哪种方式比较好呢?
这种问题显然没有答案,得看更具体的场景。
你甚至可以不用单例,在主页类中聚合几个子页面,然后点击导航到子页面就好。

现在回到使用单例的情况,
如果你viewmodel中聚合了不少model,并且model可能在其他页面也有使用,那显然对于这些model是应该做单例化的。

如果你viewmodel中有许多独立的状态项,只记录该页面的情况,和model几乎无关。那将整个ViewModel单例也是合理的。

如果你View中有一些联动的对象,比如Canvas,你在Canvas上画了一些画,而Canvas是属于View的。那将View做单例也很合理。

最终到底是用哪种方式,没有一个明确的答案。目前只能根据实际情况选取一种看似合理的方式,通过实践来检验。


三、总结

单例是很基础的设计模式,记住它是为了 保证一个类在程序中只有一个实例,并提供一个访问它的全局访问点 即可。

常见的应用场景,用户状态、配置文件、数据库连接池等。
在多页面用到同一个model时也可以使用。有些场景的使用上不必过于纠结,可达到效果即可。

相关文章:

C#上位机中的单例应用思考

文章目录 一、前言二、上位机单例应用场景2.1 上位机2.2 单例及其应用2.3 上位机中的应用2.3.1 用户登录信息2.3.2 配置文件2.3.3 数据连接池 2.4 一个应用场景的思考 三、总结 一、前言 之前写过一篇关于单例的文——C#中单例模式的实现&#xff0c;讲了讲单例是什么以及在C#…...

Python分享之redis

String 操作 redis中的String在在内存中按照一个name对应一个value来存储 set() #在Redis中设置值&#xff0c;默认不存在则创建&#xff0c;存在则修改 r.set(name, zhangsan) 参数&#xff1a; set(name, value, exNone, pxNone, nxFalse, xxFalse) ex&#xff…...

Linux常用命令——dd命令

在线Linux命令查询工具 dd 复制文件并对原文件的内容进行转换和格式化处理 补充说明 dd命令用于复制文件并对原文件的内容进行转换和格式化处理。dd命令功能很强大的&#xff0c;对于一些比较底层的问题&#xff0c;使用dd命令往往可以得到出人意料的效果。用的比较多的还是…...

DETR-《End-to-End Object Detection with Transformers》论文精读笔记

DETR&#xff08;基于Transformer架构的目标检测方法开山之作&#xff09; End-to-End Object Detection with Transformers 参考&#xff1a;跟着李沐学AI-DETR 论文精读【论文精读】 摘要 在摘要部分作者&#xff0c;主要说明了如下几点&#xff1a; DETR是一个端到端&am…...

网络流量监控-sniffnet

{alert type“info”} 今天来分享一个监控流量的应用sniffnet。 github项目地址&#xff1a;https://github.com/GyulyVGC/sniffnet {/alert} 可以在github的readme上看到这个程序有的特性&#xff1a; 为什么要介绍它呢&#xff1a;主要是多线程、跨平台、可靠、操作简单 我…...

验证go循环删除slice,map的操作和map delete操作不会释放底层内存的问题

目录 切片 for 循环删除切片元素其他循环中删除slice元素的方法方法1方法2&#xff08;推荐&#xff09;方法3 官方提供的方法结论 切片 for 循环删除map元素goalng map delete操作不会释放底层内存go map原理源码CRUD查询新增 操作注意事项map元素是无法取址的map是线程不安全…...

C++二级题2

数字字符求和 #include<iostream> #include<string.h> #include<stdio.h> #include<iomanip> #include<cmath> #include<bits/stdc.h> int a[2000][2000]; int b[2000]; char c[2000]; long long n; using namespace std; int main() {ci…...

DataWhale 机器学习夏令营第三期——任务二:可视化分析

DataWhale 机器学习夏令营第三期 学习记录二 (2023.08.23)——可视化分析1.赛题理解2. 数据可视化分析2.1 用户维度特征分布分析2.2 时间特征分布分析 DataWhale 机器学习夏令营第三期 ——用户新增预测挑战赛 学习记录二 (2023.08.23)——可视化分析 2023.08.17 已跑通baseli…...

ubuntu 上安装flutter dart android studio

因为国内网站不能使用 使用一下&#xff1a; vi ~/.bashrc 最后添加 export FLUTTER_STORAGE_BASE_URLhttps://mirrors.cloud.tencent.com/flutter export PUB_HOSTED_URLhttps://mirrors.tuna.tsinghua.edu.cn/dart-pub export PATH$PATH:/usr/local/go/bin export GOPROXY…...

【Golang】go交叉编译

交叉编译是用来在一个平台上生成另一个平台的可执行程序 。Go 命令集是原生支持交叉编译的。 Mac下编译&#xff1a;Linux 或 Windows 的可执行程序 # linux 可执行程序 CGO_ENABLED0 GOOSlinux GOARCHamd64 go build main.go # Windows可执行程序 CGO_ENABLED0 GOOSwindow…...

【人工智能】—_贝叶斯网络、概率图模型、全局语义、因果链、朴素贝叶斯模型、枚举推理、变量消元

文章目录 频率学派 vs. 贝叶斯学派贝叶斯学派Probability&#xff08;概率&#xff09;:独立性/条件独立性&#xff1a;Probability Theory&#xff08;概率论&#xff09;:Graphical models &#xff08;概率图模型&#xff09;什么是图模型&#xff08;Graphical Models&…...

学习笔记:ROS使用经验( 查看rostopic的信息)

查看topic的信息 要查看ROS中的话题信息&#xff0c;你可以使用以下命令&#xff1a; 1.查看所有活动话题&#xff1a; $ rostopic list这将列出当前运行的所有活动话题。 2.查看特定话题的消息类型&#xff1a; $ rostopic info <topic_name>将<topic_name>替…...

数据库——redis内存淘汰,持久化机制

文章目录 Redis 内存淘汰机制了解么&#xff1f;⭐了解操作系统中lru并尝试用java实现lru 2.Redis 持久化机制(怎么保证 Redis 挂掉之后再重启数据可以进行恢复)快照&#xff08;snapshotting&#xff09;持久化&#xff08;RDB&#xff09;AOF&#xff08;append-only file&am…...

亚马逊云科技 云技能孵化营 我也说ai

自从chatgpt大火以后&#xff0c;我也关注了人工智能方面的东西&#xff0c;偶尔同学推荐参加了亚马逊云科技云技能孵化营活动&#xff0c;免费学习了亚马逊云科技和机器学习方面的知识&#xff0c;还获得了小礼品&#xff0c;现在将活动及心得分享给大家。 活动内容&#xff…...

『PyQt5-基础篇』| 04 Qt Designer的初步快速了解

04 Qt Designer的初步快速了解 1 Qt Designer入口2 Qt Designer-Widget Box2.1 窗口部件盒(Widget Box)2.2 Layouts布局2.3 Spacers间隔部件2.4 Button按钮2.5 Item Views(Model-Based)2.6 Item Widgets(Item-Based)2.7 Containers容器2.8 Input Widget输入部件2.9 Display W…...

SpringCloud学习笔记(十一)_Hystrix仪表盘

我们来看一下如何使用它吧 1.引入依赖 1 2 3 4 5 6 7 8 9 10 11 12 | <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </depende…...

# ruby安装设置笔记

ruby安装设置笔记 文章目录 ruby安装设置笔记1 克隆并设置环境变量2 安装ruby3 设置ruby4 设置源5 安装bundler6 检查安装后的软件版本7 ubuntu 20.04 默认ruby环境 系统自带的ruby版本低了&#xff0c;需要手动安装更高版本&#xff08;使用rbenv方式&#xff09; 环境&#x…...

关于对文件路径权限判断的记录

首先需要添加引用 using System.Security.AccessControl;以下为具体代码&#xff0c;其中fileServerPath为需要判断的文件路径 #region Authority judgmentDirectorySecurity fileAcl Directory.GetAccessControl(fileServerPath);var rules fileAcl.GetAccessRules(true, t…...

git 基础

1.下载安装Git&#xff08;略&#xff09; 2.打开git bash窗口 3.查看版本号、设置用户名和邮箱 用户名和邮箱可以随意起&#xff0c;与GitHub的账号邮箱没有关系 4.初始化git 在D盘中新建gitspace文件夹&#xff0c;并在该目录下打开git bash窗口 git init 初始化完成后会…...

C语言网络编程实现广播

1.概念 如果同时发给局域网中的所有主机&#xff0c;称为广播 我们可以使用命令查看我们Linux下当前的广播地址&#xff1a;ifconfig 2.广播地址 以192.168.1.0 (255.255.255.0) 网段为例&#xff0c;最大的主机地址192.168.1.255代表该网段的广播地址&#xff08;具体以ifcon…...

贵阳婚礼西服定制攻略:面料、工艺、版型避坑指南

婚礼西装是男士婚礼造型的核心&#xff0c;区别于日常商务正装&#xff0c;婚礼西服更看重版型精致度、面料质感、上身挺拔感以及镜头适配度。在贵阳备婚的新人&#xff0c;大多会放弃成品西装&#xff0c;选择专属定制服务。但本地婚礼西服定制市场参差不齐&#xff0c;很多新…...

华硕笔记本终极性能控制指南:用G-Helper完全替代Armoury Crate

华硕笔记本终极性能控制指南&#xff1a;用G-Helper完全替代Armoury Crate 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zen…...

HarmonyOS ArkTS DateUtil 日期增减与日历计算完整指南

文章目录 背景一、引言二、日期增减方法详解使用示例 三、日历计算方法详解四、Demo 演示&#xff1a;日期增减结果展示五、Demo 演示&#xff1a;月历视图完整实现六、日历视图关键点解析为什么要填充前置空格&#xff1f;getLastDayOfMonth 的实现技巧 七、小结 背景 近期发现…...

智能体所有权与版权:AI Agent Harness Engineering 创造的作品归谁所有?

1. 标题选项 《AI Agent创作版权迷局破解:从Harness工程原理到所有权划分的完整指南》 《智能体作品归谁?AI Agent Harness Engineering场景下的版权规则深度拆解》 《告别权属纠纷:一文搞懂AI Agent生成内容的所有权、版权与收益分配规则》 《Harness工程视角下的AI创作权:…...

基于可解释机器学习的城市人口流动空间降尺度分析实践

1. 项目概述&#xff1a;从宏观到微观&#xff0c;解码城市脉搏在城市的肌理中&#xff0c;人口的流动如同血液的循环&#xff0c;承载着经济活力、社会互动与空间结构的全部信息。无论是城市规划师优化公交线路&#xff0c;还是商业分析师评估店铺选址&#xff0c;亦或是公共卫…...

基于随机森林的低成本传感器机器学习校准实践指南

1. 项目概述&#xff1a;当低成本传感器遇上机器学习校准在物联网和智能感知系统铺天盖地的今天&#xff0c;低成本传感器几乎无处不在。从监测办公室的空气质量&#xff0c;到追踪城市街道的噪音污染&#xff0c;再到农业大棚里的温湿度控制&#xff0c;这些价格亲民的“小眼睛…...

破解材料数据荒:合成数据与随机森林预测聚合物阻燃性能

1. 项目概述与核心挑战在材料研发领域&#xff0c;尤其是涉及公共安全的聚合物阻燃性研究&#xff0c;传统实验方法正面临巨大瓶颈。想象一下&#xff0c;你是一位材料工程师&#xff0c;需要设计一种用于高铁内饰或高层建筑电缆护套的新型聚合物&#xff0c;其阻燃性能必须满足…...

艾尔登法环存档迁移终极指南:3分钟解决角色转移难题

艾尔登法环存档迁移终极指南&#xff1a;3分钟解决角色转移难题 【免费下载链接】EldenRingSaveCopier 项目地址: https://gitcode.com/gh_mirrors/el/EldenRingSaveCopier 还在为《艾尔登法环》存档版本不兼容而烦恼吗&#xff1f;EldenRingSaveCopier 是你的终极解决…...

【DeepSeek漏洞扫描辅助实战指南】:20年安全专家亲授3大避坑法则与5步提效流程

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek漏洞扫描辅助的核心价值与适用边界 DeepSeek漏洞扫描辅助并非通用型渗透测试引擎&#xff0c;而是一个聚焦于大语言模型&#xff08;LLM&#xff09;应用层安全的轻量级分析工具。其核心价值在…...

DeepSeek安全测试辅助Prompt工程白皮书(含17个CVE靶场验证指令模板)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek安全测试辅助 DeepSeek系列大模型在代码生成、漏洞模式识别与安全上下文理解方面展现出独特优势&#xff0c;可作为安全测试工程师的智能协作者。其对OWASP Top 10、CWE分类体系及常见PoC结构具…...