单例模式

单例模式

定义:
Ensure a class has one instance, and provide a global point of access to it.
确保一个类只有一个实例,并且提供一个全局访问的途径。

一个系统中我们定义一个文件系统来管理所有的文件操作,单例模式的经典实现如下:

1.经典实现
class FileSystem
{
public:
  static FileSystem& instance()
  {
    // Lazy initialize.
    if (instance_ == NULL) instance_ = new FileSystem();
    return *instance_;
  }

private:
  FileSystem() {}

  static FileSystem* instance_;
};

但这种实现在并发环境下无法正常运作,所以我们可以进行如下修改:

2.线程安全实现
class FileSystem
{
public:
  static FileSystem& instance()
  {
    static FileSystem *instance = new FileSystem();
    return *instance;
  }

private:
  FileSystem() {}
};

c++11中确保局部静态变量只初始化一次,所以是线程安全的。

3.这种单例实现方式的好处:
  • 仅用到时才会创建
  • 运行时初始化,这样就可以获取相关运行时的信息
  • 可以创建单例的子类来实现跨平台
class FileSystem
{
public:
  static FileSystem& instance();

  virtual ~FileSystem() {}
  virtual char* readFile(char* path) = 0;
  virtual void  writeFile(char* path, char* contents) = 0;

protected:
  FileSystem() {}
};

FileSystem& FileSystem::instance()        //根据不同的平台创建不同的实例
{
  #if PLATFORM == PLAYSTATION3
    static FileSystem *instance = new PS3FileSystem();
  #elif PLATFORM == WII
    static FileSystem *instance = new WiiFileSystem();
  #endif

  return *instance;
}

class PS3FileSystem : public FileSystem
{
public:
  virtual char* readFile(char* path)
  { 
    // Use Sony file IO API...
  }

  virtual void writeFile(char* path, char* contents)
  {
    // Use sony file IO API...
  }
};

class WiiFileSystem : public FileSystem
{
public:
  virtual char* readFile(char* path)
  { 
    // Use Nintendo file IO API...
  }

  virtual void writeFile(char* path, char* contents)
  {
    // Use Nintendo file IO API...
  }
};
4.单例带来的问题

4.1它是全局变量

  • 对于大规模程序而言,全局变量使得代码出错定位变得困难。
  • 会使各个模块间的耦合度上升。
  • 由于是全局变量,它会导致并发程序间的交互变得复杂难以确定。

4.2懒汉初始化的弊端
- 在游戏进行中时,第一次遇到资源加载初始化,可能会导致一些卡顿。
- 内存分配的掌控难度加大,因为你不知道何时会将内存分配。
饿汉式单例:

class FileSystem
{
public:
  static FileSystem& instance() { return instance_; }

private:
  FileSystem() {}

  static FileSystem instance_;
};

将实例变为静态变量可以解决这些问题,但这种包装的意义又何在,因为毕竟它的访问效果和全局静态变量一致,但方式更加麻烦。

5.较好的方式

  显然在一个游戏中,完全避免全局变量也不现实,毕竟每个游戏都有一个游戏类,掌控着游戏总体的运行情况,所以我们可以尽量减少全局型的类,将它们放在原有的全局类中:

class Game
{
public:
  static Game& instance() { return instance_; }

  // Functions to set 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_;
};
//使用
Game::instance().getAudioPlayer().play(VERY_LOUD_BANG);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值