阅读源码学设计模式-单例模式

640?wx_fmt=png

有些编码套路是公认的,大家都参照其编写符合可观赏性的代码,那就是设计模式

现在.NETcore 默认提供了DI功能,那我想设计一个全局的引擎类,进行注入服务、解析服务、配置中间件。并且要求该引擎类全局唯一,其他地方不能进行实例化。那单例模式就派上用场了。单例模式官方定义:

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类成为单例类,它提供全局访问的方法。

伪代码实现需求

 public class AAEngine    {        private static AAEngine aAEngine = null;        private AAEngine() { }        //获取实例        public static AAEngine GetInstance()        {            if (aAEngine == null)            {                aAEngine = new AAEngine();            }            return aAEngine;        }        //添加服务到容器        public  void ConfigureService()        {            Console.WriteLine("添加服务到容器");        }        //添加中间件到请求管道        public  void ConfigureRequestPipeline()        {            Console.WriteLine("添加中间件到请求管道");        }        //解析服务        public  void Resolve<T>() where T : class        {            Console.WriteLine("解析服务");        }
}


在Main函数中调用

//单例模式        static void runSingleton()        {            var aAEngine = AAEngine.GetInstance();            aAEngine.ConfigureService();            aAEngine.ConfigureRequestPipeline();            Console.WriteLine("Oh yeah 单例模式! ");        }

输出

640?wx_fmt=png

小结:从实例代码中我们看到构造函数设置了级别为private,这样可以防止外部进行new实例化,外部可以通过GetInstance方法获取实例对象。实例代码其实是有点瑕疵的在多线程的情况下,会违背单例的初衷,我们下面进行如何解决这个问题。

突然脑海中闪现出曾经的面试场景,饿汉式单例和懒汉式单例,或许对问题有所有帮助;

饿汉式单例

饿汉试单例是在类加载的时候就已经创建了对象。代码如下

public class AAEngine1    {        private static AAEngine1 aAEngine = new AAEngine1();        private AAEngine1() { }        //获取实例        public static AAEngine1 GetInstance()        {            return aAEngine;        }
//添加服务到容器 public void ConfigureService() { Console.WriteLine("添加服务到容器"); } //添加中间件到请求管道 public void ConfigureRequestPipeline() { Console.WriteLine("添加中间件到请求管道"); } //解析服务 public void Resolve<T>() where T : class { Console.WriteLine("解析服务"); } }
小结:在类被加载时,静态变量aAEngine会被初始化,AAEngine1类的唯一实例将会创建,则多线程并发的场景下,也可确保单例对象的唯一性;那什么是懒汉式单例呢?其实最上面的AAEngine就是懒汉式单例,在多线程并发的场景下懒汉式单例有问题,如何解决 答案是通过锁的方式。

懒汉式单例+线程锁

懒汉式单例有延迟Lazy的思想,只有在需要的时候才去加载实例。在多线程并发的场景下我们使用双重检查锁定(Double-Check Locking)。完成代码如下:

private static AAEngine aAEngine = null;        private static object lockObj=new object();        private AAEngine() { }        //获取实例        public static AAEngine GetInstance()        {            //第一重验证            if (aAEngine == null)            {                lock (lockObj)                {                    //第二重验证                    if (aAEngine==null)                    {                        aAEngine = new AAEngine();                    }                }            }            return aAEngine;        }

单例模式在开源Nop项目中实践

为了配合你没有阅读过Nop项目源码,我会把涉及到单例的几个类源码贴出来。主要设计到3个类Singleton、IEngine、EngineContext。

Singleton类

640?wx_fmt=gif

 public class Singleton<T> : BaseSingleton    {        private static T instance;
/// <summary> /// The singleton instance for the specified type T. Only one instance (at the time) of this object for each type of T. /// </summary> public static T Instance { get => instance; set { instance = value; AllSingletons[typeof(T)] = value; } } }
IEngine类
public interface IEngine    {        /// <summary>        /// 添加配置服务 Add and configure services        /// </summary>        /// <param name="services">Collection of service descriptors</param>        /// <param name="configuration">Configuration of the application</param>        /// <param name="nopConfig">Nop configuration parameters</param>        /// <returns>Service provider</returns>        IServiceProvider ConfigureServices(IServiceCollection services, IConfiguration configuration, NopConfig nopConfig);
/// <summary> /// 配置请求管道 Configure HTTP request pipeline /// </summary> /// <param name="application">Builder for configuring an application's request pipeline</param> void ConfigureRequestPipeline(IApplicationBuilder application);
/// <summary> /// 解析服务 Resolve dependency /// </summary> /// <typeparam name="T">Type of resolved service</typeparam> /// <returns>Resolved service</returns> T Resolve<T>() where T : class;
/// <summary> /// 解析服务 Resolve dependency /// </summary> /// <param name="type">Type of resolved service</param> /// <returns>Resolved service</returns> object Resolve(Type type);
/// <summary> /// 解析所有服务Resolve dependencies /// </summary> /// <typeparam name="T">Type of resolved services</typeparam> /// <returns>Collection of resolved services</returns> IEnumerable<T> ResolveAll<T>();
/// <summary> /// Resolve unregistered service /// </summary> /// <param name="type">Type of service</param> /// <returns>Resolved service</returns> object ResolveUnregistered(Type type); }
EngineContext 引擎上下文类
 #region Methods
/// <summary> /// Create a static instance of the Nop engine. /// </summary> [MethodImpl(MethodImplOptions.Synchronized)] public static IEngine Create() { //create NopEngine as engine return Singleton<IEngine>.Instance ?? (Singleton<IEngine>.Instance = new NopEngine()); }
/// <summary> /// Sets the static engine instance to the supplied engine. Use this method to supply your own engine implementation. /// </summary> /// <param name="engine">The engine to use.</param> /// <remarks>Only use this method if you know what you're doing.</remarks> public static void Replace(IEngine engine) { Singleton<IEngine>.Instance = engine; } #endregion
#region Properties
/// <summary> /// Gets the singleton Nop engine used to access Nop services. /// </summary> public static IEngine Current { get { if (Singleton<IEngine>.Instance == null) { Create(); }
return Singleton<IEngine>.Instance; } }
#endregion }

从nop的源码中我们发现,他使用的懒汉式单例(含双重检查锁定),外部访问IEngine实例是通过EngineContext上下文来访问的。在创建IEngine实例方法create()时,使用时的 [MethodImpl(MethodImplOptions.Synchronized)]特性,表示create方法只能由一个线程执行,类似lock锁。

如何使用,代码如下

 //create engine and configure service provider var engine = EngineContext.Create(); var serviceProvider = engine.ConfigureServices(services, configuration, nopConfig);  。。。。。。。。。。。。 EngineContext.Current.Resolve<IScheduleTaskService>();

nop封装的优秀的代码,也收录到我的开源项目中了,喜欢可以star下 https://github.com/ChengLab/AAFrameWork

640?wx_fmt=jpeg


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

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

相关文章

我终于知道post和get的区别

IT界知名的程序员曾说&#xff1a;对于那些月薪三万以下&#xff0c;自称IT工程师的码农们&#xff0c;其实我们从来没有把他们归为我们IT工程师的队伍。他们虽然总是以IT工程师自居&#xff0c;但只是他们一厢情愿罢了。码农&#xff1a;你知道get和post请求到底有什么区别&am…

【译】使用Blazor构建桌面应用

随着最近.NET Core 3的正式发布&#xff0c;我认为我会尝试一个有趣的小实验。我喜欢使用Electron来创建基于Web的桌面应用程序。我想了解有关Blazor&#xff08;ASP.NET系列的最新成员&#xff09;的更多信息。在这篇文章中&#xff0c;我将向您确切演示如何在15分钟内开始使用…

CAP的学习和应用

前言:用CAP有一段时间了,这里简单记录一下,这么好用的东西,小伙伴们赶紧上车吧一.CAP使用场景?平时工作中经常使用到MQ,如(kafka,rabbitmq...),用来简单的发布/订阅,经常会遇到以下几个问题常用方案,把SQL放前面,MQ放后面,MQ执行失败了,我们把整个SQL进行回滚,这种方案在单应用…

[功能发布]Excel催化剂地图可视化功能正式发布,欢迎使用!

地图可视化功能开发完成已过去1个多月&#xff0c;文章的阅读量与初定传播目标相差甚远。但因着热爱分享的缘故&#xff0c;在阅读量未及预期时&#xff0c;仍然破例对其功能进行发布。若真正喜爱Excel催化剂所开发的地图可视化&#xff0c;可通过完成小任务来获取使用资格。再…

WebAssembly生态将完善网络安全性

近日 Mozilla、Fastly、Intel 与 Red Hat 宣布成立联合组织 Bytecode Alliance&#xff08;字节码联盟&#xff09;&#xff0c;该联盟旨在通过协作实施标准和提出新标准&#xff0c;以完善 WebAssembly 在浏览器之外的生态。WebAssembly 也叫 Wasm&#xff0c;它是为基于栈的虚…

我们终于可以把 bug 留给子孙后代了

“ 阅读本文大概需要 4 分钟。 ”今天在聊项目之前&#xff0c;我们先来聊一下历史。中学时候拿到的第一本历史书&#xff0c;上面是从智人的起源讲起的&#xff0c;他轻轻掠过尧舜禹&#xff0c;秦始皇统一六国&#xff0c;千古一相李斯。他喊二川溶溶&#xff0c;流入宫墙。五…

30分钟无坑部署K8S单Master集群

Jesse导读&#xff1a;11月9号&#xff0c;我在中国.NET开发者峰会&#xff08;.NET Conf China 2019)上分享了之前ASP.NET Core和Kubernetes做微服务的经验&#xff0c;在10号的时候又联合张善友、陈计节两位大佬一起做了一个6个小时的动手实践&#xff0c;得到了非常好的反馈…

亲自实践Blazor构建桌面应用程序

首先是安装.NET Core 3.0 与Node.js.Net Core 版本为&#xff1a;3.0.100Node.js安装版本为&#xff1a;v12.13.0用到的8个命令mkdir blazor-electron-democd blazor-electron-demodotnet new blazorserver --no-httpsdotnet add package ElectronNET.APIdotnet new tool-manif…

行云万里,转型未来 | 行云创新受邀参加2019中国.NET开发者峰会

2019 年 11 月 9 日&#xff0c;中国 .NET 开发者峰会&#xff08;.NET Conf China 2019&#xff09;在上海拉开帷幕&#xff0c;这是中国 .NET 社区的年度盛会。行云创新受邀参加了此次峰会&#xff0c;为当前最热门的科技专题带来了精彩的演讲&#xff0c;与全国的 .NET 开发…

西安活动 | 云时代,享未来 .NET 线下沙龙

活动介绍:在云时代到来的今天&#xff0c;越来越多的应用已经依赖于云而构建&#xff0c;这正得益于云给软件开发带来的低成本&#xff0c;易扩展&#xff0c;可重用的便捷之处。.NET Core平台就是为云而诞生的&#xff0c;毫无疑问它是构建云应用的首要之选。已经磨练5年时间&…

.NET手撸绘制TypeScript类图——下篇

.NET手撸绘制TypeScript类图——下篇在上篇的文章中&#xff0c;我们介绍了如何使用 .NET解析 TypeScript&#xff0c;这篇将介绍如何使用代码将类图渲染出来。类型定义渲染不出意外&#xff0c;我们继续使用 FlysEngine。虽然文字排版没做过&#xff0c;但不试试怎么知道好不好…

China .NET Conf 2019-.NET技术架构下的混沌工程实践

这个月的8号、9号&#xff0c;个人很荣幸参加了China.NET Conf 2019 , 中国.NET开发者峰会&#xff0c;同时分享了技术专题《.NET技术架构下的混沌工程实践》&#xff0c;给广大的.NET开发小伙伴介绍混沌工程和高可用性改造实践。会后大家伙聚餐的时候&#xff0c;陈计节老师建…

分布式应用框架 Dapr

微服务架构已成为构建云原生应用程序的标准,微服务架构提供了令人信服的好处&#xff0c;包括可伸缩性&#xff0c;松散的服务耦合和独立部署&#xff0c;但是这种方法的成本很高&#xff0c;需要了解和熟练掌握分布式系统。为了使用所有开发人员能够使用任何语言和任何框架轻松…

.NET Core on K8S 学习与实践系列文章索引 (更新至20191116)

更新记录&#xff1a;-- 2019-11-16 增加Docker容器监控系列文章// 此外&#xff0c;今天是11月17日&#xff0c;我又老了一岁&#xff0c;祝我自己生日快乐&#xff01;近期在学习Kubernetes&#xff0c;基于之前做笔记的习惯&#xff0c;已经写了一部分文章&#xff0c;因此给…

身边的设计模式(一):单例 与 RedisCacheManager

大家好&#xff0c;以后我会用23篇文章&#xff0c;来给大家讲解设计模式&#xff0c;当然如果你看过我的项目&#xff0c;很多设计模式已经很会了&#xff0c;只是没有注意到&#xff0c;我这里会讲解一下&#xff0c;大家就会发现&#xff0c;如果你看懂了我的项目&#xff0…

Kubernetes包管理器Helm发布3.0版本

Helm 3.0 已经发布&#xff0c;该版本是 CLI 工具的最新主要版本&#xff0c;主要关注简单性、安全性和可用性&#xff0c;内容如下&#xff1a;新特性移除 Tiller&#xff08;Helm 2 是一种 Client-Server 结构&#xff0c;客户端称为 Helm&#xff0c;服务器称为 Ti…

“兼职”运维的常用命令

自从产品转到了 dotNET Core 之后&#xff0c;更深入的接触 Linux和 Docker &#xff0c;而我每天的工作中&#xff0c;有一部分时间相当于在“兼职”做一些运维的事情。下面是一些在日常中常用的命令&#xff0c;算是个备忘吧。环境操作系统&#xff1a;CentOS7Docker&#xf…

rabbitmq死信队列详解与使用

先从概念解释上搞清楚这个定义&#xff0c;死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;字面意思可以这样理解&#xff0c;一般来说&#xff0c;producer将消息投递到broker或者直接到queue里了&#xff0c;consumer从queue取出消息进行消费&#xff0c;但某些时…

使用ASP.NET Core 3.x 构建 RESTful API - 3.2 开始建立Controller和Action

Demo下面我们就来实践一下。打开之前的项目&#xff0c;并建立CompaniesController&#xff1a; 这里有6个地方比较关键&#xff0c;我们挨个看一下&#xff1a; RESTful API 或者其它Web API的Controller都应该继承于 ControllerBase 这个类&#xff08;点此查看详细的官方文档…

C++ 链表

线性表&#xff08;顺序表&#xff09;有两种存储方式&#xff1a;链式存储和顺式存储&#xff0c;顺式存储如数组&#xff0c;其内存连续分配&#xff0c;且是静态分配。链式存储&#xff0c;内存是不连续的&#xff0c;且是动态分配。前一个元素存储数据&#xff0c;后一个元…