游戏设计中的单例模式
恭喜今天股票基金大涨,哈哈。但是,加班还是要继续,加班写博客,打发一下时间。因为晚上的工作效率真的是不高呢,那就做一点总结的工作吧。
说起单例模式,恐怕大家最熟悉不过了,但是每每看到参考书或者参考资料总是觉得很揪心。因为大部分都是在写java的单例模式,又要讲到多线程状态下不能保证赋值操作和构造函数执行的顺序,所以需要改变一下写法。今天读了C++写的设计模式,才发现C++天生的避免了那些复杂的东西。
下面看一下第一个单例示例
class FileSystem
{
public:
static FileSystem& instance()
{
//惰性初始化
if (instance_ == NULL)
instance_ = new FileSystem();
return *instance_;
}
private:
FileSystem(){}
static FileSystem* instance_;
};
这算是最一般的写法了,但是不支持多线程情况,稍作修改,代码是这样的
class FileSystem
{
public:
static FileSystem& instance()
{
static FileSystem* instance = new FileSystem();
return *instance;
}
private:
FileSystem(){}
};
说一下惰性初始化,其实在游戏编程来看,单例惰性初始化并没有特别大的优势或者说好处。虽然说延迟初始化可以节省一些东西,但是也许初始化的时候正是某个玩家战斗激烈或者其他一些什么重要时刻,这时候分配内存加载资源等等,游戏也许就会表现的并不是那么流畅。而且这些单例又是不能销毁的。
可继承单例
我第一次见到这种写法是简直被惊到了,简直是完美。更完美的是我学会了用可继承单例模式来理解这种做法。代码如下
class FileSystem
{
public:
virtual ~FileSystem(){}
virtual char* readFile(char* path) = 0;
virtual void writeFile(char* path, char* contents) = 0;
};
class PS3FileSystem:public FileSystem
{
public:
virtual char* readFile(char* path)
{
//使用索尼的文件读写API......
}
virtual void writeFile(char* path char* contents)
{
//使用索尼的文件读写API......
}
};
class WiiFileSystem:public FileSystem
{
public:
virtual char* readFile(char* path)
{
//使用任天堂的文件读写API......
}
virtual void writeFile(char* path char* contents)
{
//使用任天堂的文件读写API......
}
};
//实例化FileSystem
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 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_;
};
这样,只有Game是全局可见的。函数可以通过它访问其他系统。
Game::instance().getAudioPlayer().play(VERY_LOUD_BANG);
2018年10月22日