The basic concept of a pattern can also be seen as the basic concept of program design in general: adding layers of abstraction. Whenever you abstract something, you’re isolating particular details, and one of the most compelling motivations for this is to
The most difficult part of developing an elegant and maintainable design is often discovering what we call "the vector of change." (Here, "vector" refers to the maximum gradient as understood in the sciences, and not a container class.) This means finding the most important thing that changes in your system or, put another way, discovering where your greatest cost is. Once you discover the vector of change, you have the focal point around which to structure your design.
So the goal of design patterns is to isolate changes in your code; to put it another way:
You’ve also already seen another pattern that appears in
The Singleton
Possibly the simplest design pattern is the
//: C10:SingletonPattern.cpp
#include
using namespace std;
class Singleton {
static Singleton s;
int i;
Singleton(int x) : i(x) { }
Singleton& operator=(Singleton&); // Disallowed
Singleton(const Singleton&); // Disallowed
public:
static Singleton& instance() {
return s;
}
int getValue() { return i; }
void setValue(int x) { i = x; }
};
Singleton Singleton::s(47);
int main() {
Singleton& s = Singleton::instance();
cout << s.getValue() << endl;
Singleton& s2 = Singleton::instance();
s2.setValue(9);
cout << s.getValue() << endl;
} ///:~
The key to creating a Singleton is to prevent the client programmer from having any control over the lifetime of the object. To do this, declare all constructors private, and prevent the compiler from implicitly generating any constructors. Note that the copy constructor and assignment operator are declared private to prevent any sort of copies being made.
You must also decide how you’re going to create the object. Here, it’s created statically, but you can also wait until the client programmer asks for one and create it on demand. This is called
If you return a pointer instead of a reference, the user could inadvertently delete the pointer, so the implementation above is considered safest. In any case, the object should be stored privately.
You provide access through public member functions. Here, instance( ) produces a reference to the Singleton object. The rest of the interface (getValue( ) and setValue( )) is the regular class interface.
Note that you aren’t restricted to creating only one object. This technique easily supports the creation of a limited pool of objects. In that situation, however, you can be confronted with the problem of sharing objects in the pool. If this is an issue, you can create a solution involving a check-out and check-in of the shared objects.
Variations on Singleton