游戏编程模式:单例模式

“确保一个类只有一个实例,并为其提供一个全局访问入口。”

模式动机:

有些情况下,一个类如果有多个实例就不能正常运作。(这个类与一个维持着自身全局状态的外部系统进行交互的情况。)

如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。

一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。

模式定义:

单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。

单例模式的要点有三个:

  1. 某个类只能有一个实例

  2. 它必须自行创建这个实例

  3. 它必须自行向整个系统提供这个实例

单例模式是一种对象创建型模式。单例模式又名单件模式或单态模式。

优点:

  • 如果我们不使用它,就不会创建实例。(节省内存和CPU周期,单例仅在第一次被访问的时候实例化,那么如果我们的游戏始终不使用它,它就不会初始化。)
  • 它在运行时初始化。使用静态类来替代单例模式是一个常用的方法,但是静态类会自动初始化。这使得它不能获取游戏运行期间才得到的消息,同时也无法保证相互依赖的静态数据间的初始化顺序。单例可以将初始化延后,以至于其所需要的所有信息都可以得到。
  • 可以继承单例。

缺点:

  • 它们令代码晦涩难懂。
  • 全局变量促进了耦合。
  • 对并发并不友好。

写法:

懒汉式(线程不安全):

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton
{
private static Singleton instance;
private Singleton(){}

public static Singleton getInstance()
{
if(instance == null)
instacne = new Singleton();
}
return instance;
}

问题:当多个线程并行调用getInstance时,会创建多个实例,在多线程下不能正常工作。

懒汉式(线程安全):

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton
{
private static Singleton instance;
private Singleton(){}
[MethodImpl(MethodImplOptions.Synchronized)]
public static Singleton getInstance()
{
if(instance == null)
instacne = new Singleton();
}
return instance;
}

问题:保证了线程安全,但是任何时候只能由一个线程调用getInstance方法,但是同步操作只需要在第一次调用时才被需要。

(双检锁?)