C#--设计模式之单例模式

单例模式大概是所有设计模式中最简单的一种,如果在面试时被问及熟悉哪些设计模式,你可能第一个答的就是单例模式。

单例模式的实现分为两种:

  • 饿汉式:在静态构造函数执行时就立即实例化。
  • 懒汉式:在程序执行过程中第一次需要时再实例化。

两者有各自适用的场景,实现方式也都很简单,唯一在设计时要考虑的一个问题就是:实例化时需要保证线程安全

1. 饿汉式

饿汉式实现很简单,在静态构造函数中立即进行实例化:

public class Singleton
{
    private static readonly Singleton _instance;
    static Singleton()
    {
        _instance = new Singleton();
    }

    public static Singleton Instance
    {
        get
        {
            return _instance;
        }
    }
}

注意,为了确保单例性,需要使用 readonly 关键字声明实例不能被修改

以上写法可简写为:

public class Singleton
{
    private static readonly Singleton _instance = new Singleton();
    public static Singleton Instance
    {
        get
        {
            return _instance;
        }
    }
}

这里的 new Singleton() 等同于在静态构造函数中实例化。在 C# 7 中还可以进一步简写如下:

public class Singleton
{
    public static Singleton Instance { get; } = new Singleton();
}

一句代码就搞定了,此写法,实例化也是在默认的静态构造函数中进行的。如果是饿汉式需求,这种实现是最简单的。有人会问这会不会有线程安全问题,如果多个线程同时调用 Singleton.Instance 会不会实例化了多个实例。不会,因为 CLR 确保了所有静态构造函数都是线程安全的

注意,不能这么写:

public class Singleton
{
    public static Singleton Instance => new Singleton();
}
// 等同于:
public class Singleton
{
    public static Singleton Instance
    {
        get { return new Singleton(); }
    }
}

这样会导致每次调用都会创建一个新实例。

2. 懒汉式

懒汉式单例实现需要考虑线程安全问题,先来看一段经典的线程安全的单列模式实现代码:

public sealed class Singleton
{
    private static volatile Singleton _instance;
    private static readonly object _lockObject = new Object();

    public static Singleton Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_lockObject)
                {
                    if (_instance == null)
                    {
                        _instance = new Singleton();
                    }
                }
            }
            return _instance;
        }
    }
}

网上搜索 C# 单例模式,大部分都是这种使用 lock 来确保线程安全的写法,这是经典标准的单例模式的写法,没问题,很放心。在 lock 里外都做一次 instance 空判断,双保险,足以保证线程安全和单例性。但这种写法似乎太麻烦了,而且容易写错。早在 C# 3.5 的时候,就有了更好的写法,使用 Lazy<T>
示例代码:

public class LazySingleton
{
    private static readonly Lazy<LazySingleton> _instance =
        new Lazy<LazySingleton>(() => new LazySingleton());

    public static LazySingleton Instance
    {
        get { return _instance.Value; }
    }
}

调用示例:

public class Program
{
    public static void Main()
    {
        var instance = LazySingleton.Instance;
    }
}

使用 Lazy 可以使对象的实例化延迟到第一次被调用的时候执行,通过访问它的 Value 属性来创建并获取实例,并且读取一个 Lazy 实例的 Value 属性只会执行一次实例化代码,确保了线程安全。

3. 应用示例

static void Main(string[] args)
{
    LazySingleton p1 = LazySingleton.Instance();
    p1.GetName();
    LazySingleton p2 = LazySingleton.Instance();
    p2.GetName();
    if (p1 == p2)
    {
        Console.WriteLine("他们是同一个人!");
    }
    else
    {
        Console.WriteLine("他们不是同一人!");
    }
    Console.ReadLine();
}

public class LazySingleton
{
    private static volatile LazySingleton instance = null;//保证instance在所有线程中同步
    //private防止类在外部被实例化
    private LazySingleton()
    { }
    public static LazySingleton Instance()
    {
        if (instance == null)
        {
            instance = new LazySingleton();
        }
        return instance;
    }

    public void GetName()
    {
        Console.WriteLine("詹姆斯");
    }
}

程序运行结果:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++类的定义和对象的创建

一、问题引入 C类和对象到底是什么意思&#xff1f; 1、C 中的类&#xff08;Class&#xff09;可以看做C语言中结构体&#xff08;Struct&#xff09;的升级版。结构体是一种构造类型&#xff0c;可以包含若干成员变量&#xff0c;每个成员变量的类型可以不同&#xff1b; …

K8s的高可用搭建

高可用技术搭建 在master节点上需要部署&#xff1a;keepalived、haproxy

Linux 信号signal处理机制

Signal机制在Linux中是一个非常常用的进程间通信机制&#xff0c;很多人在使用的时候不会考虑该机制是具体如何实现的。signal机制可以被理解成进程的软中断&#xff0c;因此&#xff0c;在实时性方面还是相对比较高的。Linux中signal机制的模型可以采用下图进行描述。 每个进程…

openGauss学习笔记-33 openGauss 高级数据管理-视图

文章目录 openGauss学习笔记-33 openGauss 高级数据管理-视图33.1 语法格式33.2 参数说明33.3 示例 openGauss学习笔记-33 openGauss 高级数据管理-视图 视图与基本表不同&#xff0c;是一个虚拟的表。数据库中仅存放视图的定义&#xff0c;而不存放视图对应的数据&#xff0c…

Misc取证学习

文章目录 Misc取证学习磁盘取证工具veracryto挂载fat文件DiskGenius 磁盘取证例题[RCTF2019]disk 磁盘[](https://ciphersaw.me/ctf-wiki/misc/disk-memory/introduction/#_2)内存取证工具volatility 内存取证例题数字取证赛题0x01.从内存中获取到用户admin的密码并且破解密码 …

Maven: ‘mvn‘ is not recognized as an internal or external command

下载并配置好Maven之后&#xff0c;CMD测试安装是否成功&#xff1a;mvn -v 提示&#xff1a; mvn is not recognized as an internal or external command, operable program or batch file. 检查环境变量&#xff1a; MAVEN_HOME: %MAVEN_HOME%\bin: 看上去没问题&#x…

【Java】异常处理 之 Java的异常

Java的异常 在计算机程序运行的过程中&#xff0c;总是会出现各种各样的错误。 有一些错误是用户造成的&#xff0c;比如&#xff0c;希望用户输入一个int类型的年龄&#xff0c;但是用户的输入是abc&#xff1a; // 假设用户输入了abc&#xff1a; String s "abc&quo…

uniapp微信小程序底部弹窗自定义组件

基础弹窗效果组件 <template><view><viewclass"tui-actionsheet-class tui-actionsheet":class"[show ? tui-actionsheet-show : ]"><view class"regional-selection">底部弹窗</view></view><!-- 遮罩…

行业追踪,2023-08-07

自动复盘 2023-08-07 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

el-popover使用自定义图标

使用el-popover实现鼠标点击或浮动到自定义图标上弹出表格弹窗&#xff0c;官方文档上使用的是按钮el-button&#xff0c;如果想换成图标或其他的组件的话直接把el-button替换掉即可。注意替换之后的组件一定要加slot“reference”&#xff0c;不然组件是显示不出来的。 代码如…

前端小练习:案例5.律动爱心

目录 一.效果预览图 二.实现思路 ​编辑 1.html部分 2.css部分 三.完整代码 一.效果预览图 二.实现思路 想要实现爱心律动效果并不难&#xff0c;核心点是关键帧动画。 定义律动爱心需要的元素块&#xff0c;使用定位或者弹性布局等方法&#xff08;定位元素不适合布局&…

zookeeper和kafka

目录 一、zookeeper理论 1.1、zookeeper定义 1.2、zookeeper工作机制 1.3、zookeeper特点 1.4、zookeeper的数据结构 1.5、zookeeper应用场景 1.6、zookeeper的选举机制 二、部署Zookeeper 集群 2.1、环境准备 2.2、安装 Zookeeper 2.3、修改配置文件 2.4、配置…

百度智能创做AI平台

家人们好&#xff0c;在数字化时代&#xff0c;人工智能正引领着一场前所未有的创新浪潮。今天&#xff0c;我们将为大家介绍百度智能创做AI平台&#xff0c;这个为创意赋能、助力创作者的强大工具。无论你是创意工作者、内容创作者&#xff0c;还是想要释放内心创造力的个人&a…

Linux下进程的特点与环境变量

目录 进程的特点 进程特点的介绍 进程时如何实现并发性的 进程间如何切换 概念铺设 PC指针 上下文 环境变量 PATH 修改PATH HOME SHELL env 命令行参数 什么是命令行参数&#xff1f; 打印命令行参数 通过函数获得环境变量 getenv 命令行参数 env 修改环境变…

JavaScript(四)DOM及CSS操作

1、DOM简介 DocumentType: Html的声明标签 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Docume…

从零开始,开发自己的微信小程序小白也能搞定

微信小程序已经成为了很多创业者实现梦想的利器。乔拓云平台提供了一套完整的小程序创建流程&#xff0c;让你轻松打造属于自己的小程序商城。下面就跟随这篇文章&#xff0c;一步一步来看如何创建一个成功的微信小程序商城吧&#xff01; 首先&#xff0c;你需要登录乔拓云平台…

【数据结构】实现单链表的增删查

目录 1.定义接口2.无头单链表实现接口2.1 头插addFirst2.2 尾插add2.3 删除元素remove2.4 修改元素set2.5 获取元素get 3.带头单链表实现接口3.1 头插addFirst3.2 尾插add3.3 删除元素remove3.4 判断是否包含元素element 1.定义接口 public interface SeqList<E>{//默认…

第九节 文件操作

文章目录 1. 引言2. 基本的文件操作2.1 打开文件2.1.1 mode 访问模式2.1.2 文件不存在,则创建文件2.1.3 二进制打开文件2.1.4 打开文件时&#xff0c;指定编码方式 2.2 关闭文件2.2.1 with 打开语句结构 2.3 文件的读写2.3.1 写入文件内容2.3.2 读取文件2.3.2.1 read&#xff0…

TCP的三次握手四次挥手

TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手&#xff1a;为了对每次发送的数据量进行跟踪与协商&#xff0c;确保数据段的发送和接收同步&#xff0c;根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系&#xff0c;并建立虚连接。 四次挥手&a…

JVM系统优化实践(24):ZGC(一)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 截止到目前&#xff0c;算上ZGC&#xff0c;Java一共有九种类型的GC&#xff0c;它们分别是&#xff1a; 1、Serial GC 串行/作用于新生代/复制算法/响应速度优先/适用于单…