The Uno Counter-Pattern

The Uno Counter-Pattern — Spanish for "one", and a tribute to the card game Uno — is meant to counter The Singleton Anti-Pattern. The idea is to disguise the fact that only one instance of the object can exist for whatever reason from client code, soas to discourage writing code that depends on this fact as part of the interface, hopefully preventing any code (or introducing code smell) from releasing that limitation.

The Basic Concept

The key differences between The Singleton Anti-Pattern and The Uno Counter-Pattern are:

  1. Singletons publicly expose a reference to the one and only instance, whereas Uno classes treat this as an implementation detail
  2. Singletons have a unique construction method, whereas Uno classes are instantiated as any other would be — they simply have the precondition that no other instances have already been created.

Uno in C++

The following is a rough example of the Uno pattern applied to a GLUT window wrapper class. While it supports only a single instance, some fairly trivial refactoring, changing window* window::instance; into std::map< GLuint , window* > window::instances; — which does not change window()'s public interface in the slightest (except for removing the "no previous instances" precondition of window's constructors, which will not break any existing code) — this easily transforms into multiple-instance aware code, while requiring no big structural changes to code that uses the window class.

class window : public boost::noncopyable {
public:
    window() {
        assert(!instance); instance = this;
        glutCreateWindow( "Default Window" );
        register_callbacks();
    }
    window( const char * title ) {
        assert(!instance); instance = this;
        glutCreateWindow( title );
        register_callbacks();
    }
    ~window() {
        assert(instance==this); instance = 0;
    }

    void idle();
    void display();
    void keyboard( char key , int x , int y );
private:
    static window* instance;
    static void idle_cb() { assert(instance); instance->idle(); }
    static void display_cb() { assert(instance); instance->display(); }
    static void keyboard_cb( char key , int x , int y ) { assert(instance); instance->keyboard(key,x,y); }
    void register_callbacks() {
        glutIdleFunc( &idle_cb );
        glutDisplayFunc( &display_cb );
        glutKeyboardFunc( &keyboard_cb );
    }
};

window* window::instance = 0;