设计模式 <创建型> | 单例模式

单例模式(Singleton)

单例设计模式(Singleton Design Pattern),一个类在只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模。

结构图:

适用场景:

  1. 无状态的工具类可以使用单例模式。

角色:

  1. 单例类(Singleton):负责生成单例并返回

优点:

  1. 可以保证对象的唯一性,用于解决资源竞争等场景。

缺点:

  1. oop支持不友好。
  2. 会隐藏类之间的依赖关系(单例类不需要显示创建、不需要依赖参数传递,在函数中直接调用就可以了。如果代码比较复杂,这种调用关系就会非常隐蔽。)
  3. 代码的可测试性不好,不方便mock。
  4. 不支持有参数的构造函数

代码(C#)

饿汉式,在程序启动的时候就会创建好实例对象,优点是使用的时候不需要再加载了,缺点是如果启动时饿汉单例过多会导致程序启动过慢。饿汉式是线程安全的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

public class SingletonClass
{
private static SingletonClass _singleton = new SingletonClass();

/// <summary>
/// 私有化构造函数,防止外部创建
/// </summary>
/// <returns></returns>
private SingletonClass()
{
}

/// <summary>
/// 饿汉模式
/// </summary>
/// <returns></returns>
public static SingletonClass GetSingletonClass()
{
return _singleton;
}
}

懒汉式,等需要使用到这个对象的时候在加载。懒汉在创建的时候需要手动加锁保证线程安全。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

public class SingletonClass
{
private static readonly object Lock = new object();

private static SingletonClass? _singleton2;

/// <summary>
/// 私有化构造函数,防止外部创建
/// </summary>
/// <returns></returns>
private SingletonClass()
{
}

/// <summary>
/// 懒汉模式
/// </summary>
/// <returns></returns>
public static SingletonClass GetSingletonClass2()
{
// 提前判断,防止每次都需要上锁
if (_singleton2 == null)
{
// 防止多线程重复创建
lock (Lock)
{
if (_singleton2 == null)
return _singleton2 = new SingletonClass();
else
return _singleton2;
}
}

return _singleton2;
}
}

静态内部类实现单例,类都有一个隐藏属性 before field init,JIT 编译器可以在首次访问一个静态字段或者一个静态/实例方法之前,或者创建类型的第一个实例之前,随便找一个时间生成调用。具体调用时机由CLR决定,它只保证访问成员之前会执行(隐式)静态构造函数,但可能会提前很早就执行。理解成静态成员会在类第一次使用之前的任何时间初始化,这种方式也是线程安全的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class SingletonStaticClass
{
/// <summary>
/// 私有化构造函数,防止外部创建
/// </summary>
private SingletonStaticClass()
{
}

private static class CteateInstanceClass
{
static CteateInstanceClass()
{
}
// 创建需要的单例对象
public static SingletonStaticClass Instance = new();
}


/// <summary>
/// 对外公开的创建对象方法
/// </summary>
/// <returns></returns>
public static SingletonStaticClass GetSingletonClass()
{
return CteateInstanceClass.Instance;
}
}

使用.Net 默认 DI 实现,DI 会在程序启动的时候就在根容器创建好实例。

1
2
3
4
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<SingletonClass>();

最后

和静态类的区别:

  1. 单例是有实例的代表的一个对象,而静态类代表是一组常驻内存的方法。
  2. 单例对象可以被延迟初始化。而静态类总是在类被加载的时候就初始化。
  3. 单例可以继承类、接口,而静态类不能。

性能方面,静态类会比单例模式更加好。因为静态方法在编译期就完成了静态绑定。

如果类中没有保存任何的状态性质的属性,只是提供些方法就可以使用静态类。

如果在项目中要使用单例模式,建议使用 DI 来创建单例或者使用内部静态类。


设计模式 <创建型> | 单例模式
http://example.com/posts/10991.html
作者
她微笑的脸y
发布于
2023年2月21日
许可协议