夸克之书

  • 首页
  • 科普
  • 笔记
  • .NET/C#
  • 物联网
  • 算法
  • Linux
  • 树莓派
夸克之内,别有洞天
  1. 首页
  2. .NET/C#
  3. 正文

23种常见的设计模式(1):单例模式

2019-12-29 2323点热度 0人点赞 0条评论

首先一个问题,什么是单例模式?根据我的理解,单例模式重点突出一个“单”字,无论干什么都是在同一个类中进行的,一个类只能生成一个对象,所有的操作都通过这个对象来进行操作。

很显然,要控制一个类只能提供一个单一的对象供外部调用使用,就需要将构造行数私有化,让其他人(类)不能创建我这个类。同时,要对外提供服务,我就需要将这个已经由我创建好了的对象公布出去,让别的人(类)通过我公布的实例来对我进行访问。

以一个Log类作为例子,在项目开发的生命周期中,需要在无数的地方打印日志。不可能每次调用一下日志打印就要去创建一个日志打印对象,这样多浪费性能。而通过单例模式创建日志对象后,每次访问日志打印方法时,获取创建好了的单例即可。

整个日志类代码如下:

public class Log
{
    public static Log _logger = null;

    /// <summary>
    /// 私有化构造函数
    /// </summary>
    private Log()
    {

    }

    /// <summary>
    /// 创建单例时的锁
    /// </summary>
    private static readonly object locker = new object();

    /// <summary>
    /// 提供对外的访问
    /// 懒汉式创建方式
    /// </summary>
    public static Log Instance
    {
        get
        {
            if(_logger == null)
            {
                lock (locker)
                {
                    if(_logger == null)
                    {
                        _logger = new Log();
                    }
                }
            }
            return _logger;
        }
    }

    /// <summary>
    /// 写日志的方法
    /// </summary>
    /// <param name="text"></param>
    public void Write(string text)
    {
        if (string.IsNullOrEmpty(text))
        {
            return;
        }
        Console.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]{text}");
    }
}

写日志时,通过调用Write方法,打印日志即可:

static void Main(string[] args)
{
    Log.Instance.Write("这个是要打印的Log.");
    Console.ReadKey(false);
}

运行结果:

%title插图%num
demo运行结果

分析代码可以看到,在创建单例时,用了lock来保证线程安全。为什么要这样做呢?来看下下面这段非线程安全创建单例的代码:

public static Log Instance
{
    get
    {
        if (_logger == null)
        {
            _logger = new Log();
        }
        return _logger;
    }
}

当我们将这段代码应用在多线程高并发环境中时,如果两个线程同时调用Instance后,就能出现创建创建两次对象的情况(每个线程创建一遍)。为了避免出现这种不可预料的错误,就需要在创建单例对象的时候进行加锁,保证从始至终都是一个对象来提供服务。

那么单例模式有什么优点和缺点呢?

优点:

· 单例模式仅在内存中创建了一个实例,减小内存开支。当遇到一个对象需要频繁的进行创建和销毁,而创建和销毁时的性能又不能得到保障时,就可以通过创建单例来避免这种性能损失。
· 避免对资源的多重占用,例如以上的日志Demo,如果要写日志到文件的话,就可以避免对日志文件的多重占用(日志类仅作为一个demo)

缺点:

· 单例模式扩展非常困难,想要扩展,可能只有通过修改代码来进行扩展了。
· 单例模式与单一职责原则冲突,单例模式中一个类要进行的操作肯定不止一种。

分析完优缺点,再更具单例模式特性,很容易就能想到在哪里场景下用单例模式比较合适。比如:

· 生成唯一序列号的场景,单例模式可以保证生成的UUID是完全独立的。
· 需要优化重复IO读写的场景。
· 各种工具类(实际上我觉得各种工具类适合使用扩展方法)

题外话

其实单例也可以不单例,一个单例模式中虽然提供服务的是一个实例,但是一个实例的内部也可以多个对象的组合呀??!

本篇代码下载:点此下载

参考:

1、《设计模式之禅》 秦小波 著

本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可
标签: 暂无
最后更新:2020-12-13

afirefish

这个人很懒,什么都没留下

打赏 点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论
放松一下
https://www.quarkbook.com/wp-content/uploads/2021/05/凤凰传奇-海底(Live).flac
分类
  • .NET/C#
  • Linux
  • 树莓派
  • 物联网
  • 科普
  • 笔记
  • 算法
  • 默认
最新 热点 随机
最新 热点 随机
Windows Server 2022安装Intel I225-V驱动 System.Text.Json与Newtonsoft.Json Json序列化与反序列化性能对比 R86S散热改造 Windows移除多余输入法'Unknown Locale (qaa-Latn)' 【算法】具有层级关系的城市,例如"中国 广州","中国 浙江 杭州" 一个 List 最后应该是转成树状图输出 树莓派安装Golang环境
Windows Server 2022安装Intel I225-V驱动
PVE重启后LVM Thin数据丢失,错误:Volume group "****" has insufficient free space (128 extents): 4048 required. 树莓派PWM风扇控制 宿主机不能Ping通虚拟机中的Windows Server 单机Docker搭建FastDFS Vieu主题作者疑似跑路?这人品?!!! 解决js异步同时请求接口的问题
最近评论
afirefish 发布于 2 个月前(11月28日) 非常感谢,非常棒!
》随缘《 发布于 3 个月前(11月20日) 最新【一键处理】方法: https://github.com/MrXhh/VSTools/rele...
管理员 发布于 8 个月前(06月22日) emmmm....服务器好一点???
wking 发布于 9 个月前(05月23日) 请问贵博客是怎么优化的,网页响应速度非常快。我博客同样的WordPress和kratos主题,但点一...
去月球 发布于 1 年前(01月17日) 如果使用CSI的摄像头应该怎么修改命令呢
书签
  • 打赏
  • 毒鸡汤
  • 米店
  • 金鱼直播间

COPYRIGHT © 2022 quarkbook.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

蜀ICP备15036129号-9

登录
注册|忘记密码?