Why are Singletons needed, and how do they solve the issue?


 

The issue

 

Consider that we want a single copy of an object that any other object can access. We might, for example, want a data repository, and not especially want to make a normal object that we have to pass a reference to into every one of hundreds of objects that work with it. It would be much nicer to have a single object that we could just use by name.

We might think the solution lies in a static variable. Static variables exist at the class level, not the object level, so all objects of a class share the same variable. We could, therefore, do this:

class Storage {
	double data = 0;
	void setData(double dataIn) {
		data = dataIn;
	}
}	

class A {
	static Storage store = new Storage();
}

class B {
	A.store.setData(10);
}

class C {
	A.store.setData(20);
}

In this case, as "store" is a static variable and exists for the class "A", class B and C both alter the same variable without having to have the same object made from class A. Here's what the latter would look like; it would be more complicated:

class B {
	A a = new A();
	a.setData(10);
	C c = new C();
	c.setA(a);
	c.run();
}

class C {
	A a = null;
	void setA(A aIn) {
		a = aIn;
	}
	void run() {
		a.setData(20);
	}
}

Plainly the static version is a lot simpler. However, it doesn't stop anyone doing this:

class D {
	Storage store = new Storage();
}

That is, making a second Storage object, and, indeed, a non-static one. This could easily confuse issues.

Therefore, what we need is a way of ensuring there can never, ever, be two versions of Storage. Static alone doesn't solve this. What does, however, (generally) is the Singleton pattern. We'll build one up a stage at a time to show how.


 

How Singletons solve it

 

With a Singleton, we set up a static variable that we can access through the class. We might as well make this the Singleton's own class, keeping it all close together (and, as we'll see, helping us lock down reuse of this class for other objects):

class Storage {
	double data = 0;
	void setData(double dataIn) {
		data = dataIn;
	}
	
	static Storage store = new Storage();
	
}

As the variable contains all the code in the class, this allows us to use it thus:

class B {
	Storage.store.setData(10);
}

Not only can we access this through the class, as it is static, it is also the only copy.

However, as we know, it isn't polite to directly access variables like this -- we go through Accessor methods. In this case, by tradition, we call the method getInstance(), as we are getting an instance object containing the whole class. Note that this is static too, so we can access it through the class:

class Storage {
	double data = 0;
	void setData(double dataIn) {
		data = dataIn;
	}
	
	static Storage store = new Storage();
	static Storage getInstance() {
		return store;
	}
}

Infact, calling the constructor like this doesn't work as it would generate the store object again, again calling the constructor. To ensure it is only done once, the first time we want it, we do this:

class Storage {
	double data = 0;
	void setData(double dataIn) {
		data = dataIn;
	}
	
	static Storage store = null;
	static Storage getInstance() {
		if (store == null) {	
			store = new Storage();
		}
		return store;
	}
}

Thus, we use the Singleton like this:

class B {
	Storage.getInstance().setData(10);
	//or 
	Storage s = Storage.getInstance();
	s.setData(10);
}

Finally, we want to stop anyone else making another Storage class object. We do this by putting in a blank constructor set to private. From then onwards, no one can make an object of this type. The exception is Storage itself, which can still access the private method:

class Storage {
	double data = 0;
	void setData(double dataIn) {
		data = dataIn;
	}
	
	static Storage store = null;
	
	private Storage() {}
	
	static Storage getInstance() {
		if (store == null) {	
			store = new Storage();
		}
		return store;
	}
}

This is our full Singleton, and can be used safe in the knowledge that we can:

1) Have only one copy.
2) Access it easily through the class, rather than having to pass references to it around.
3) Make sure no one else can make a non-static object out of it.