描述:
保证一个类只有一个实例,并且提供了访问该实例的全局访问点.
实现方案
私有构造器保证它是唯一的,公开的静态方法instance()提供了访问实例的接口.
在首次被请求时,instance()负责惰性实例化该单例.
多线程情况下,C++11标准保证了本地(局部)静态变量只会初始化一次,因此是线程安全的.
class Singleton { public: static Singleton& instance() { static Singleton *instance = new Singleton(); return *instance; } private: Singleton() {} };复制代码
给实例提供更方便的访问方法
便利的访问是使用单例的一个主要原因,可以在不同的地方访问实例,代价就是不想要对象的地方,也能轻易使用.
除了单例,代码中获取实例的几种方式
- 作为函数参数传进来
渲染对象的函数,需要传入一个表示图形设备的对象,管理渲染状态,将其传给渲染函数是自然地..
相反,AI函数虽然也需要写日志,但是日志不是它关注的核心,Log作为参数传进来就很奇怪.
2) 从基类中获得
很多游戏有浅层但是宽泛的继承层次,比如,GameObject基类,每个游戏中的对象都继承它,很大一部分代码存在于这些派生出来的子类中,意味着这些类有对同样事务的相同获取方法.
class GameObject { // 使用protect让派生对象使用实例被限制在子类的沙盒中 protected: Log& getLog() { return log_; } private: static Log& log_; }; class Enemy : public GameObject { void doSomething() { getLog().write("I can log!"); } };复制代码
- 已经是全局的对象中获取
我们可以让现有的全局对象捎带需要的对象,来减少全局对象的数目.
这样只要Game是全局可见的,就可以通过接口访问其他系统.
class Game { public: static Game& instance() { return instance_; } // 设置log_, et. al. …… Log& getLog() { return *log_; } FileSystem& getFileSystem() { return *fileSystem_; } AudioPlayer& getAudioPlayer() { return *audioPlayer_; } private: static Game instance_; Log *log_; FileSystem *fileSystem_; AudioPlayer *audioPlayer_; };复制代码
- 从服务器定位器中获得
定义一个类,目标就是为对象提供全局访问,这种模式被成为服务器定位器模式.