什么是单例模式
在开发时,如果要调取另一个public
类中的方法时,有两种方法。
第一种方法是使用静态方法,用static
关键字标记方法让这个方法在程序运行时就存放在内存中,例如public static void Test(){}
。
第二种方法就是使用单例模式调用,单例模式与静态方法比较像,只不过单例模式可以在方法被用到的时候才将类实例化,在这之前甚至可以将其设为null
。
显而易见,使用单例模式可以避免在方法或对象没有被用到的时候就在内存中实例化,另外单例模式保证了在同一时间仅仅会存在一个类的实例。
单例模式的应用非常广泛,比如说你不可能在你的电脑上同时打开两个任务管理器,如果你可以的话就去把电脑修一下吧。
单例模式的单线程实现
假如我们要在单线程中实现类Singleton
的单例模式。1
2
3public class Singleton{
}
它的格式是
private 类名(){}
1 | private Singleton(){} //单例模式的构造函数 |
然后,新建这个类的私有静态实例
它的格式是private static 类名 变量名
1
private static Singleton instance = null;
如上所述可以先把它设为null
,在用到的时候才实例化。
下面定义单例模式的外部接口,其他类通过调用这个方法得到类的实例
它的格式是public static 类名 方法名(){}
1
2
3
4
5
6public static Singleton GetInstance(){
if(instance == null) //如果当前不存在类的实例就创建一个
instance = new Singleton();
return instance; //返回类的实例
}
组合起来就是单线程的单例模式实现方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class Singleton{
private Singleton(){} //单例模式的构造函数
private static Singleton instance = null; //创建私有静态实例并设为null
public static Singleton GetInstance(){
if(instance == null) //如果当前不存在类的实例就创建一个
instance = new Singleton();
return instance; //返回类的实例
}
public void SayHello(){ //测试函数
Console.Write("Hello!");
}
}
public class Test{
public void SingletonTest(){
Singleton.GetInstance().SayHello(); //单例模式调用方法
}
}
单例模式的多线程实现
在多线程开发时使用单例模式需要引用线程锁lock()
,它的作用是保持程序互斥运行,具体原理是在多个线程运行到互斥的代码块时,给他们一个排序,同一时间只允许一个线程通过,并且在当前线程通过时,其他线程只能等待当前线程运行完这段代码块。
在类中定义一个locker
1
private static readonly object locker = new object();
修改外部接口的方法1
2
3
4
5
6
7
8
9public static Singleton GetInstance(){
if(instance == null){
lock(locker){ //运行到这里时按次序经过线程锁
if(instance == null)
instance = new Singleton();
}
}
return instance;
}
在这个单例模式中,类的初始实例为空(instance = null
),多个线程运行到线程锁,一个线程先进入代码块实例化了类instance
,其他的线程就不需要再次进行实例化操作,保证了只存在一个实例化的特性。
C#语言中特别的单例模式
我是进行Unity3D开发的,用到的语言类型是C#,偶然情况下发现了一种非常简单的单例模式实现方式。
直接上代码1
2
3
4public class Singleton2{
private Singleton2(){}
public static readonly Singleton2 instance = new Singleton2();
}
在这个实现方式中,私有的构造函数确保类不能被外部实例化,内部的实例化instance
经过readonly
修饰不能被修改,这样就保证了在程序中无时无刻都有且仅有一个类的实例instance
,省掉了通过方法调用获取实例的过程GetInstance()
,它的缺陷就是在程序运行时就产生了类的实例化。
但恕我直言,这真的是我见过最懒的方式了。。。