继承实现单例模式的探索(一)
前言
之前看到朋友采用继承的方式来实现单例模式,觉得很厉害,随后自己去探索了一番,以前实现单例模式都是把代码内联到具体的类中,这使得工程中每次需要使用单例模式时,都采用拷贝的方式,增加了很多冗余代码,并且难以规范单例的统一标准,使得代码不方便扩展和管理。这次探索找到了一种实现方式,先记录下来,后续如果有其它方式再发表系列文章,示例代码为C#。
代码
v1.0版本
using System;/// <summary>
/// 单例模式基类
/// </summary>
/// <typeparam name="T">单例类型</typeparam>
public abstract class Singleton<T>
where T : class, new()
{public static T instance => _instance.Value;static bool _unlock;static readonly Lazy<T> _instance = new Lazy<T>(() =>{_unlock = true;return new T();});protected Singleton(){if (!_unlock)throw new InvalidOperationException("Singleton:The ctor is proxied by singleton and cannot be called from outside.");_unlock = false;}
}
v1.1
using System;/// <summary>
/// 单例模式基类
/// </summary>
/// <typeparam name="T">单例类型</typeparam>
public abstract class Singleton<T>
where T : class, new()
{public static T instance => _instance.Value;static bool _unlock;static readonly Lazy<T> _instance = new Lazy<T>(Create);static T Create(){_unlock = true;T item = new T();_unlock = false;return item;}protected Singleton(){if (!_unlock)throw new InvalidOperationException("Singleton:The ctor is proxied by singleton and cannot be called from outside.");}
}
测试
单例基类
using System;/// <summary>
/// 单例模式基类
/// 版本1.0
/// </summary>
/// <typeparam name="T">单例类型</typeparam>
// public abstract class SingletonWithTest<T>
// where T : class, new()
// {
// public static T instance => _instance.Value;
// static bool _unlock;
// static readonly Lazy<T> _instance = new Lazy<T>(() =>
// {
// _unlock = true;
// return new T();
// });// protected SingletonWithTest()
// {
// if (!_unlock)
// {
// // throw new InvalidOperationException("Singleton:The ctor is proxied by singleton and cannot be called from outside.");
// Console.WriteLine($"Singleton({GetHashCode()}):The ctor is proxied by singleton and cannot be called from outside.");
// return;
// }
// _unlock = false;
// Console.WriteLine("*************************");
// }
// }/// <summary>
/// 单例模式基类
/// 版本1.1
/// </summary>
/// <typeparam name="T">单例类型</typeparam>
public abstract class SingletonWithTest<T>
where T : class, new()
{public static T instance => _instance.Value;static bool _unlock;static readonly Lazy<T> _instance = new Lazy<T>(Create);static T Create(){_unlock = true;T item = new T();_unlock = false;return item;}protected SingletonWithTest(){if (!_unlock){// throw new InvalidOperationException("Singleton:The ctor is proxied by singleton and cannot be called from outside.");Console.WriteLine($"Singleton({GetHashCode()}):The ctor is proxied by singleton and cannot be called from outside.");return;}Console.WriteLine("*************************");}
}
单例继承类
public class TestA : SingletonWithTest<TestA>
{public readonly string key;public TestA() { key = "Default A"; }public TestA(string key) { this.key = key; }
}public class TestB : SingletonWithTest<TestB>
{public readonly string key;public TestB() { key = "Default B"; }public TestB(string key) { this.key = key; }
}public class TestC : SingletonWithTest<TestC>
{public readonly string key;public TestC() { key = "Default C"; }public TestC(string key) { this.key = key; }
}public class TestD : SingletonWithTest<TestD>
{public readonly string key;public TestD() { key = "Default D"; }public TestD(string key) { this.key = key; }
}public class TestE : SingletonWithTest<TestE>
{public readonly string key;public TestE() { key = "Default E"; }public TestE(string key) { this.key = key; }
}public class TestF : SingletonWithTest<TestF>
{public readonly string key;public TestF() { key = "Default F"; }public TestF(string key) { this.key = key; }
}
测试代码
// ********************************* 创建实例测试:通过 ********************************* // 直接创建实例测试:通过
// TestA a = new TestA(); // 无法通过 new + 无参ctor 创建实例
// TestA a1 = new TestA("A1"); // 无法通过 new + 有参ctor 创建实例
// TestA a2 = Activator.CreateInstance<TestA>(); // 无法通过 Activator 创建实例
// TestA? a2 = Activator.CreateInstance(typeof(TestA), "A1") as TestA; // 无法通过 Activator 创建实例// ********************************* 线程安全测试:通过 *********************************Thread t1, t2, t3, t4, t5, t6;// 打印同一单例的 HashCode 测试:通过
t1 = new Thread(() => Console.WriteLine("Thread1:" + TestA.instance.GetHashCode()));
t2 = new Thread(() => Console.WriteLine("Thread2:" + TestA.instance.GetHashCode()));
t3 = new Thread(() => Console.WriteLine("Thread3:" + TestA.instance.GetHashCode()));
t4 = new Thread(() => Console.WriteLine("Thread4:" + TestA.instance.GetHashCode()));
t5 = new Thread(() => Console.WriteLine("Thread5:" + TestA.instance.GetHashCode()));
t6 = new Thread(() => Console.WriteLine("Thread6:" + TestA.instance.GetHashCode()));// 使用单例的同时直接创建该单例类型实例测试:通过
// t1 = new Thread(() => Console.WriteLine("Thread1:" + TestA.instance.GetHashCode()));
// t2 = new Thread(() => Console.WriteLine("Thread2:" + new TestA().GetHashCode()));
// t3 = new Thread(() => Console.WriteLine("Thread3:" + new TestA().GetHashCode()));
// t4 = new Thread(() => Console.WriteLine("Thread4:" + new TestA().GetHashCode()));
// t5 = new Thread(() => Console.WriteLine("Thread5:" + new TestA().GetHashCode()));
// t6 = new Thread(() => Console.WriteLine("Thread6:" + new TestA().GetHashCode()));// 同时使用不同单例的测试:通过
// t1 = new Thread(() => Console.WriteLine("Thread1:" + TestA.instance.GetHashCode()));
// t2 = new Thread(() => Console.WriteLine("Thread2:" + TestB.instance.GetHashCode()));
// t3 = new Thread(() => Console.WriteLine("Thread3:" + TestC.instance.GetHashCode()));
// t4 = new Thread(() => Console.WriteLine("Thread4:" + TestD.instance.GetHashCode()));
// t5 = new Thread(() => Console.WriteLine("Thread5:" + TestE.instance.GetHashCode()));
// t6 = new Thread(() => Console.WriteLine("Thread6:" + TestF.instance.GetHashCode()));// 使用单例的同时创建其它单例类型的实例测试:通过
// t1 = new Thread(() => Console.WriteLine("Thread1:" + TestA.instance.GetHashCode()));
// t2 = new Thread(() => Console.WriteLine("Thread2:" + new TestB().GetHashCode()));
// t3 = new Thread(() => Console.WriteLine("Thread3:" + new TestC().GetHashCode()));
// t4 = new Thread(() => Console.WriteLine("Thread4:" + new TestD().GetHashCode()));
// t5 = new Thread(() => Console.WriteLine("Thread5:" + new TestE().GetHashCode()));
// t6 = new Thread(() => Console.WriteLine("Thread6:" + new TestF().GetHashCode()));t1.Start();
t2.Start();
t3.Start();
t4.Start();
t5.Start();
t6.Start();t1.Join();
t2.Join();
t3.Join();
t4.Join();
t5.Join();
t6.Join();
优缺点分析
| 优点 | 1.通过继承实现单例; 2.可以通过单例基类规范统一标准; 3.线程安全; 4.无法通过除单例基类提供的静态属性instance以外的其它方式获取其派生类实例,外部通过new关键字显示调用构造函数或反射等其它获取实例的方式创建派生类实例将触发异常; 5.派生类的无参构造函数用于初始化; 6.按需加载,延迟初始化。 |
|---|---|
| 缺点 | 1.要求派生类的无参构造函数公开; 2.派生类对外部始终开放无参构造函数,无法避免new关键字的显式调用所触发的异常; |
版本改进
| V1.1 | 1.将延迟初始化的工厂方法从Lambda表达式替换为本地静态方法,因为_unlock相对于Lazy<T>是外部引用,所以不可避免存在创建闭包的开销,所以改为本地静态方法进行改进; 2._unlock在构造函数中进行重置会存在线程安全的问题,放在作为延迟初始化的工厂方法的本地静态方法中可以保证线程安全。 |
|---|---|
| ...... |
系列文章
继承实现单例模式的探索(二)
如果这篇文章对你有帮助,请给作者点个赞吧!
相关文章:
继承实现单例模式的探索(一)
前言 之前看到朋友采用继承的方式来实现单例模式,觉得很厉害,随后自己去探索了一番,以前实现单例模式都是把代码内联到具体的类中,这使得工程中每次需要使用单例模式时,都采用拷贝的方式,增加了很多冗余代码…...
【代码实现】opencv 高斯模糊和pytorch 高斯模糊
wiki百科 Gaussian Blur,也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等图像处理软件中广泛使用的处理效果,通常用它来减少图像噪声以及降低细节层次。 opencv实现 opencv实现高斯滤波有两种方式, 1、是使用自带的cv2…...
python基础语法2
文章目录 1.顺序语句2.条件语句2.1 语法格式 3.缩进与代码块4.空语句 pass5.循环语句5.1 while循环5.2 for循环 5.3 continue与break 1.顺序语句 默认情况下,python的代码都是按照从上到下的顺序依次执行的。 print(hello ) print(world)结果一定是hello world。写…...
linux第一课:下载与安装
这是我的个人复习笔记,草稿箱字太多会卡就发这了,欢迎大家阅读。 Kali Linux,黑客必备神器。跟着我,带你从入门到入狱! 第一课,下载与安装。 第一步: 在官网下载Centos镜像:http…...
虚拟机添加共享文件夹后仍无法显示文件
参考: https://blog.csdn.net/Pretender_1205/article/details/134859089 进入/mnt/hgfs目录下执行 sudo mount -t fuse.vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other/mnt/hgfs 是挂载点,也可以修改为其他挂载点-o allow_other表示允许其他用户(普通用户)访问共…...
OSPF协议
基础知识 OSPF:开放式最短路径优先协议 (无类别链路状态IGP动态协议) OSPF的特点: 1.OSPF将自治系统划分为逻辑上的区域,使用LSA来发布路由信息,并通过OSPF报文在区域内路由器之间交互建立链路状态数据库和路由表 2.支持等开销的负载均衡…...
行为设计模式 -观察者模式- JAVA
观察者模式 一.简介二. 案例2.1 抽象主题(Subject)2.2 具体主题(Concrete Subject)2.3 抽象观察者(Observer)2.4 具体观察者(Concrete Observer)2.5 测试 三. 结论3.1 优缺点3.2 使用…...
在阿里工作是一种什么体验?
很多人都对在阿里工作感到好奇,今天就来给大家分享一下在阿里工作是一种什么体验~ 首先,先来介绍一下阿里的职位等级划分标准。 简单来讲,阿里的职位等级可以认为是 P 序列和 M 序列,但目前 M 序列已经不太对中下层员工开放了&…...
828华为云征文|华为云Flexus云服务器X实例——uniapp功能开发、搭建股票系统选择用什么服务器比较好?
在二次开发、安装搭建股票系统时,选择华为云Flexus X服务器是一个值得考虑的优质选项。以下是一些具体的建议: 测试环境:Linux系统CentOS7.6、宝塔、PHP7.3、MySQL5.7,根目录public,伪静态thinkphp,开启ssl…...
电子电路元件器介绍与选型——晶振
一、晶振 在我们使用嘉立创的时候,经常会看到晶振接到两个电容,这两个电容毫无疑问是滤波的,整个晶振其实就是一个振荡器,但这个振荡器会将其他频率给过滤掉,只保留一个频率也就是晶振的标称频率。当然上面讲的很明显是…...
【IEEE PDF eXpress】格式不对
目录 一、问题二、解决方法 一、问题 word的文档,用IEEE PDF eXpress网站生成pdf后,提交论文出现错误: Document validation failed due to the following errors: Content exceeds IEEE template margins for its format (Page 1:Bottom).…...
OpenAI全新多模态内容审核模型上线:基于 GPT-4o,可检测文本和图像
在数字时代,内容安全问题愈发受到重视。9月26日,OpenAI 正式推出了一款全新的多模态内容审核模型,名为 “omni-moderation-latest”。 该模型基于最新的 GPT-4o 技术,能够准确地识别检测有害文本图像。这一更新将为开发者提供强大…...
Visual Studio 字体与主题推荐
个人推荐,仅供参考: 主题:One Monokai VS Theme 链接:One Monokai VS Theme - Visual Studio Marketplacehttps://marketplace.visualstudio.com/items?itemNameazemoh.onemonokai 效果: 字体:JetBrain…...
信息学奥赛一本通 1416:【17NOIP普及组】棋盘 | 洛谷 P3956 [NOIP2017 普及组] 棋盘
【题目链接】 洛谷 P3956 [NOIP2017 普及组] 棋盘 ybt 1416:【17NOIP普及组】棋盘 【题目考点】 1. 深搜:深搜回溯 2. 深搜剪枝:最优化剪枝 【解题思路】 搜索从左上角到右下角的所有走法中花费金币最少的走法。 需要使用深搜回溯&…...
UE4完整教程 UE4简介 UE4学习攻略及文件格式
开头附上工作招聘面试必备问题噢~~包括综合面试题、无领导小组面试题资源文件免费!全文干货。 UE4简介学习攻略UE4Demo代码面试内容资源-CSDN文库https://download.csdn.net/download/m0_72216164/89825102 工作招聘无领导小组面试全攻略最常见面试题(第一部分)共有17章+可…...
JVM内存回收机制
目录 1.JVM运行时数据区 2.JVM类加载过程 3.双清委派模型 4.垃圾回收机制(GC) 找出谁是垃圾方案一:引用计数 找出谁是垃圾:方案二,可达性分析 释放垃圾的内存空间 判断垃圾:jvm依据对象的年龄对 对象…...
中国身份证号码校验
题目描述 第二届河南省最美教师评选开始了,每一位同学都可以投票选出你支持的人选,但是为了防止刷票,必须通过身份验证才可投票。负责投票平台后台的老大爷希望你能帮他验证身份证号的合法性,防止那些熊孩子随意刷票,…...
【Kubernetes】常见面试题汇总(五十四)
目录 120.创建 init C 容器后,其状态不正常? 特别说明: 题目 1-68 属于【Kubernetes】的常规概念题,即 “ 汇总(一)~(二十二)” 。 题目 69-113 属于【Kubernetes】的生产…...
不懂外语也能无障碍交流?探索4款超好用中英翻译工具
嘿,各位外贸流程的小伙伴们,今儿咱们来聊聊那些翻译神器,看看它们在中英文互译这条路上,是怎么给我们这些天天跟洋文打交道的哥们儿姐们儿减轻负担的。我亲身体验了福昕翻译在线、福昕翻译大师、海鲸AI翻译还有腾讯翻译君…...
C++ WebDriver扩展
概述 WebDriver协议基于HTTP,使用JSON进行数据传输,定义了client与driver之间的通信标准。无论client的实现语言(如Java或C#),都能通过协议中的endpoints准确指示driver执行各种操作,覆盖了Selenium的所有功…...
从浮点到定点:在Xilinx Vivado里给FPGA设计做‘瘦身’的实战避坑指南
从浮点到定点:Xilinx Vivado中FPGA设计的资源优化实战 当你在Vivado中完成了一个基于浮点运算的算法设计,却发现LUT占用率爆表或者时序无法收敛时,那种挫败感我深有体会。去年在做一个实时图像处理的滤波器时,我原本优雅的浮点设计…...
基于三菱PLC的自动配料控制系统的设计
基于PLC的自动配料控制系统设计【配套10000字设计lumwen,三菱PLC组态王组态等】 基于三菱PLC的自动配料控制系统的设计 混凝土搅拌站分为:砂石给料、水和一些特殊的加剂给料、传输搅拌与存储 搅拌机控制系统上电后,进入人机对话的操作界面&am…...
零代码构建智能安防平台:WVP-GB28181-Pro的5个技术突破
零代码构建智能安防平台:WVP-GB28181-Pro的5个技术突破 【免费下载链接】wvp-GB28181-pro 基于GB28181-2016、部标808、部标1078标准实现的开箱即用的网络视频平台。自带管理页面,支持NAT穿透,支持海康、大华、宇视等品牌的IPC、NVR接入。支持…...
阿里云物联网平台OTA升级避坑指南:从版本号上报到Bin文件拉取的全流程排错
阿里云物联网平台OTA升级全链路排错实战手册 当设备固件需要远程更新时,OTA技术无疑是救星。但现实往往比理想骨感——版本号莫名失踪、升级包半路"走失"、设备在关键时刻"装聋作哑"。这些问题不仅耽误进度,更可能让生产线停摆。本文…...
mT5分类增强版中文-base效果惊艳:同一输入生成‘正式/口语/幽默’三风格文本示例
mT5分类增强版中文-base效果惊艳:同一输入生成‘正式/口语/幽默’三风格文本示例 1. 模型介绍:零样本学习的文本增强利器 mT5分类增强版中文-base是一个基于mT5架构的文本增强模型,专门针对中文场景进行了深度优化。这个模型最大的特点是采…...
揭秘AI教材写作:低查重率,用AI轻松搞定教材编写难题!
编写教材需要丰富的资料作为基础,但传统的资料整理方式早已无法满足当前的需求。过去,课标文件、学术论文和教学案例等信息零散地散落在多个平台上,比如知网和教研网站,这让我们花费数天才筛选到有用的内容。而即使所有资料都收集…...
3步释放20GB空间:Windows驱动清理神器完全指南
3步释放20GB空间:Windows驱动清理神器完全指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 驱动管理痛点分析 系统臃肿的隐形杀手 随着电脑使用时间增长,Wi…...
三菱FX2N与士林变频器MODBUS通讯实战指南
1. 硬件连接:从零搭建通讯桥梁 第一次接触三菱FX2N和士林变频器的MODBUS通讯时,最让我头疼的就是硬件接线。别看只是几根线,接错了轻则通讯失败,重则烧毁端口。这里分享几个实操中容易踩的坑: 变频器端接线要点&#x…...
从宇宙到地面:解析ICRS、GCRS、CIRS、TIRS和ITRS坐标系统的层级关系与应用场景
1. 从宇宙到地球:坐标系统的层级关系 想象一下你站在夜晚的旷野中仰望星空。那些闪烁的星星看似固定不动,但实际上它们的精确位置需要用一套复杂的坐标系统来描述。从天文学研究到日常导航,不同的坐标系统就像一套精密的俄罗斯套娃࿰…...
libpcap BPF过滤器完全指南:构建高效网络数据包过滤系统
libpcap BPF过滤器完全指南:构建高效网络数据包过滤系统 【免费下载链接】libpcap the LIBpcap interface to various kernel packet capture mechanism 项目地址: https://gitcode.com/gh_mirrors/li/libpcap libpcap是一款强大的网络数据包捕获库ÿ…...
