Design Patterns in C#: Singleton
- Singleton Mechanics
- Singletons and Threads
- Recognizing Singleton
- Summary
Objects can usually act responsibly just by performing their own work on their own attributes, without incurring obligations beyond self-consistency. Some objects, though, take on increased responsibilities, such as modeling real-world entities, coordinating work, or modeling the overall state of a system. When a particular object in a system bears a responsibility on which other objects rely, you need some way of finding the responsible object. For example, you might need to find an object that represents a particular machine, or a customer object that can construct itself from data in a database, or an object that initiates system memory recovery.
When you need to find a responsible object, in some cases, the object that you need will be the only instance of its class. For example, a fireworks factory might need exactly one Factory object. In this case, you can use Singleton. The intent of the Singleton pattern is to ensure that a class has only one instance, and to provide a global point of access to it.
Singleton Mechanics
The mechanics of Singleton are more memorable than its intent. It is easier to explain how to ensure that a class has only one instance than it is to say why you might want this restriction. You might categorize _Singleton as a “creational” pattern, as Design Patterns does. You should, of course, think of patterns in whatever way helps you remember, recognize, and apply them. But the intent of the Singleton pattern implies that a specific object bears a responsibility on which other objects rely.
You have some options regarding how you create an object that takes on a unique role. But, regardless of how you create a singleton, you have to ensure that other developers don’t create new instances of the class you intend to limit.
Challenge 8.1
How can you prevent other developers from constructing new instances of your class?
A solution appears on page 363.
When you design a singleton class, you need to decide when to instantiate the single object that will represent the class. One choice is to create this instance as a static field in the class. For example, a SystemStartup class might include the line:
private static Factory _factory = new Factory();
This class could make its unique instance available through a public, static _GetFactory() method.
Rather than creating a singleton instance ahead of time, you might wait until the instance is first needed, lazy-initializing it. For example, the SystemStartup class might make its single instance available with:
public static Factory GetFactory() { if (_factory == null) { _factory = new Factory(); // ... } return _factory; }
Challenge 8.2
Why might you decide to lazy-initialize a singleton instance rather than initializing it in its field declaration?
A solution appears on page 363.