游戏引擎中经常用到单例(singleton)类,即应用程序只存在该类的一个实例,下面是它的实现方式:
1、c++ professional中的单例日志类:定义一个protected的static Logger sInstance;然后通过public静态函数
static Logger& instance();返回sInstance,从而实现对该类中函数的访问。同时,该类的构造函数是私有的,我们不能通过构造函数创建该类的实例。
Code
/**
* Logger.h
*
* Definition of a true singleton logger class.
*/
#include <iostream>
#include <fstream>
#include <vector>
class Logger
{
public:
static const std::string kLogLevelDebug;
static const std::string kLogLevelInfo;
static const std::string kLogLevelError;
// Returns a reference to the singleton Logger object
static Logger& instance();
// Logs a single message at the given log level
void log(const std::string& inMessage,
const std::string& inLogLevel);
// Logs a vector of messages at the given log level
void log(const std::vector<std::string>& inMessages,
const std::string& inLogLevel);
protected:
// Static variable for the one-and-only instance
static Logger sInstance;
// Constant for the file namename
static const char* const kLogFileName;
// Data member for the output stream
std::ofstream mOutputStream;
private:
Logger();
~Logger();
};
/**
* Logger.h
*
* Definition of a true singleton logger class.
*/
#include <iostream>
#include <fstream>
#include <vector>
class Logger
{
public:
static const std::string kLogLevelDebug;
static const std::string kLogLevelInfo;
static const std::string kLogLevelError;
// Returns a reference to the singleton Logger object
static Logger& instance();
// Logs a single message at the given log level
void log(const std::string& inMessage,
const std::string& inLogLevel);
// Logs a vector of messages at the given log level
void log(const std::vector<std::string>& inMessages,
const std::string& inLogLevel);
protected:
// Static variable for the one-and-only instance
static Logger sInstance;
// Constant for the file namename
static const char* const kLogFileName;
// Data member for the output stream
std::ofstream mOutputStream;
private:
Logger();
~Logger();
};
Code
/**
* Logger.cpp
*
* Implementation of a singleton logger class.
*/
#include <string>
#include "Logger.h"
using namespace std;
const string Logger::kLogLevelDebug = "DEBUG";
const string Logger::kLogLevelInfo = "INFO";
const string Logger::kLogLevelError = "ERROR";
const char* const Logger::kLogFileName = "log.out";
// The static instance will be constructed when the program starts and
// destructed when it ends.
Logger Logger::sInstance;
Logger& Logger::instance()
{
return sInstance;
}
Logger::~Logger()
{
mOutputStream.close();
}
Logger::Logger()
{
mOutputStream.open(kLogFileName, ios_base::app);
if (!mOutputStream.good()) {
cerr << "Unable to initialize the Logger!" << endl;
}
}
void Logger::log(const string& inMessage, const string& inLogLevel)
{
mOutputStream << inLogLevel << ": " << inMessage << endl;
}
void Logger::log(const vector<string>& inMessages, const string& inLogLevel)
{
for (size_t i = 0; i < inMessages.size(); i++) {
log(inMessages[i], inLogLevel);
}
}
int main(int argc, char** argv)
{
Logger::instance().log("test message", Logger::kLogLevelDebug);
vector<string> items;
items.push_back("item1");
items.push_back("item2");
Logger::instance().log(items, Logger::kLogLevelError);
}
/**
* Logger.cpp
*
* Implementation of a singleton logger class.
*/
#include <string>
#include "Logger.h"
using namespace std;
const string Logger::kLogLevelDebug = "DEBUG";
const string Logger::kLogLevelInfo = "INFO";
const string Logger::kLogLevelError = "ERROR";
const char* const Logger::kLogFileName = "log.out";
// The static instance will be constructed when the program starts and
// destructed when it ends.
Logger Logger::sInstance;
Logger& Logger::instance()
{
return sInstance;
}
Logger::~Logger()
{
mOutputStream.close();
}
Logger::Logger()
{
mOutputStream.open(kLogFileName, ios_base::app);
if (!mOutputStream.good()) {
cerr << "Unable to initialize the Logger!" << endl;
}
}
void Logger::log(const string& inMessage, const string& inLogLevel)
{
mOutputStream << inLogLevel << ": " << inMessage << endl;
}
void Logger::log(const vector<string>& inMessages, const string& inLogLevel)
{
for (size_t i = 0; i < inMessages.size(); i++) {
log(inMessages[i], inLogLevel);
}
}
int main(int argc, char** argv)
{
Logger::instance().log("test message", Logger::kLogLevelDebug);
vector<string> items;
items.push_back("item1");
items.push_back("item2");
Logger::instance().log(items, Logger::kLogLevelError);
}
2、Game AI ...中的代码:
和前面的基本一样,但是在getinstance中来定义一个指向该类的静态变量,效果和上面一样,该函数第一次调用时候,会创建该静态变量。
Code
class VisitBankAndDepositGold : public State<Miner>
{
private:
VisitBankAndDepositGold(){}
//copy ctor and assignment should be private
VisitBankAndDepositGold(const VisitBankAndDepositGold&);
VisitBankAndDepositGold& operator=(const VisitBankAndDepositGold&);
public:
static VisitBankAndDepositGold* Instance();
virtual void Enter(Miner* miner);
virtual void Execute(Miner* miner);
virtual void Exit(Miner* miner);
};
//----------------------------------------methods for VisitBankAndDepositGold
VisitBankAndDepositGold* VisitBankAndDepositGold::Instance()
{
static VisitBankAndDepositGold instance;
return &instance;
}
void VisitBankAndDepositGold::Enter(Miner* pMiner)
{
//on entry the miner makes sure he is located at the bank
if (pMiner->Location() != bank)
{
cout << "\n" << GetNameOfEntity(pMiner->ID()) << ": " << "Goin' to the bank. Yes siree";
pMiner->ChangeLocation(bank);
}
}
void VisitBankAndDepositGold::Execute(Miner* pMiner)
{
//deposit the gold
pMiner->AddToWealth(pMiner->GoldCarried());
pMiner->SetGoldCarried(0);
cout << "\n" << GetNameOfEntity(pMiner->ID()) << ": "
<< "Depositing gold. Total savings now: "<< pMiner->Wealth();
//wealthy enough to have a well earned rest?
if (pMiner->Wealth() >= ComfortLevel)
{
cout << "\n" << GetNameOfEntity(pMiner->ID()) << ": "
<< "WooHoo! Rich enough for now. Back home to mah li'lle lady";
pMiner->GetFSM()->ChangeState(GoHomeAndSleepTilRested::Instance());
}
//otherwise get more gold
else
{
pMiner->GetFSM()->ChangeState(EnterMineAndDigForNugget::Instance());
}
}
void VisitBankAndDepositGold::Exit(Miner* pMiner)
{
cout << "\n" << GetNameOfEntity(pMiner->ID()) << ": " << "Leavin' the bank";
}
class VisitBankAndDepositGold : public State<Miner>
{
private:
VisitBankAndDepositGold(){}
//copy ctor and assignment should be private
VisitBankAndDepositGold(const VisitBankAndDepositGold&);
VisitBankAndDepositGold& operator=(const VisitBankAndDepositGold&);
public:
static VisitBankAndDepositGold* Instance();
virtual void Enter(Miner* miner);
virtual void Execute(Miner* miner);
virtual void Exit(Miner* miner);
};
//----------------------------------------methods for VisitBankAndDepositGold
VisitBankAndDepositGold* VisitBankAndDepositGold::Instance()
{
static VisitBankAndDepositGold instance;
return &instance;
}
void VisitBankAndDepositGold::Enter(Miner* pMiner)
{
//on entry the miner makes sure he is located at the bank
if (pMiner->Location() != bank)
{
cout << "\n" << GetNameOfEntity(pMiner->ID()) << ": " << "Goin' to the bank. Yes siree";
pMiner->ChangeLocation(bank);
}
}
void VisitBankAndDepositGold::Execute(Miner* pMiner)
{
//deposit the gold
pMiner->AddToWealth(pMiner->GoldCarried());
pMiner->SetGoldCarried(0);
cout << "\n" << GetNameOfEntity(pMiner->ID()) << ": "
<< "Depositing gold. Total savings now: "<< pMiner->Wealth();
//wealthy enough to have a well earned rest?
if (pMiner->Wealth() >= ComfortLevel)
{
cout << "\n" << GetNameOfEntity(pMiner->ID()) << ": "
<< "WooHoo! Rich enough for now. Back home to mah li'lle lady";
pMiner->GetFSM()->ChangeState(GoHomeAndSleepTilRested::Instance());
}
//otherwise get more gold
else
{
pMiner->GetFSM()->ChangeState(EnterMineAndDigForNugget::Instance());
}
}
void VisitBankAndDepositGold::Exit(Miner* pMiner)
{
cout << "\n" << GetNameOfEntity(pMiner->ID()) << ": " << "Leavin' the bank";
}