creational pattern: singleton
DESCRIPTION
Creational Pattern: Singleton. Chapter 3 – Page 45. When an application needs one, and only one, instance of a particular object, proper enforcement of that object’s uniqueness and appropriate global access to the object can be problematic. - PowerPoint PPT PresentationTRANSCRIPT
Creational Pattern: SingletonWhen an application needs one, and only one, instance of a particular object, proper enforcement of that object’s uniqueness and appropriate global access to the object can be problematic.
Chapter 3 – Page 1
This is particularly useful when one object is needed to coordinate actions across a software system. One problem associated
with this pattern is the fact that it complicates unit testing, since it introduces a global state into the software system.
The Singleton PatternThe class of the single instance is responsible for access and "initialization on first use“.
Chapter 3 – Page 2
The single instance is a protected static attribute in order to guarantee that a new instance is created if one doesn’t already exist, and if one does exist, a reference to that instance is accessible.The constructor is private in order to ensure that the object can only be instantiated via the constructor.
ClientSingleton
static instance()
C++ Code for a Logger SingletonChapter 3 – Page 3
#include <string>#include <iostream>#include <fstream>#include <vector> using namespace std;
class Logger{ public: static const string kLogLevelDebug; static const string kLogLevelInfo; static const 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 string &inMessage, const string &inLogLevel);
// Logs a vector of messages at the given log level void log(const vector<string> &inMessages, const string& inLogLevel);
protected: // Static variable for the one-and-only instance static Logger sInstance;
// Constant for the file name static const char* const kLogFileName;
// Data member for the output stream ofstream mOutputStream;
private: Logger(); ~Logger();};
Chapter 3 – Page 4
const string Logger::kLogLevelDebug = "DEBUG";const string Logger::kLogLevelInfo = "INFO";const string Logger::kLogLevelError = "ERROR";
const char* const Logger::kLogFileName = "log.txt";
// The static instance will be constructed when // the program starts and destroyed when it ends.Logger Logger::sInstance;
Logger& Logger::instance(){ return sInstance;}
Logger::~Logger(){ mOutputStream.close();}
Logger::Logger(){ mOutputStream.open(kLogFileName); 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 (int i = 0; i < (int)inMessages.size(); i++) log(inMessages[i], inLogLevel);}
Chapter 3 – Page 5
void main(){ Logger::instance().log("test message", Logger::kLogLevelDebug);
vector<string> items; items.push_back("item1"); items.push_back("item2");
Logger::instance().log(items, Logger::kLogLevelError);}DEBUG: test messageERROR: item1ERROR: item2
Final contents of log.txt
Singleton Design AdvantagesChapter 3 – Page 6
• The Singleton pattern ensures that the class (not the programmer) is responsible for the number of instances created.
• Unlike static variables, the Singleton pattern is extensible, so if the software design later changes so a larger (but still controlled) number of instances is needed, only the instance() operator needs to be changed.
• Unlike global variables, singletons don’t pollute the namespace with unnecessary variables.