Singleton
Objective
Ensure the creation of a single instance for a given class.
Function
Ensure the existence of a single instance for a class and the creation of a mechanism for global access to it.
Structure
As shown in figure 1The Singleton class declares the static method obtainInstance that returns the same instance of its own class. The Singleton constructor must be hidden from the customer's code. Calling the getInstance method should be the only way to get the Singleton object.
The structure that meets this pattern is shown in Figure 1
Figure 1: UML Diagram Singleton Pattern
Applications
- The system requires exactly one instance of a class, which must be accessible to customers from a well-defined access point.
- The single instance must be extended to subclasses and clients must be able to use it without modifying their code.
Design Patterns Collaborators
- A Singleton pattern is often related to and used in the implementation of the Abstract Factory pattern, especially when it concerns a specific factory.
Scope of action
Applied at the object level.
Problem
Ensuring the creation of a single instance requires high levels of validation and a global variable; which is difficult to control when there are multiple instances of objects.
Solution
The Singleton pattern creates a class that instances the only object that will be responsible for the creation, initialization and access; this instance must be a private, since the instance creation operation must be hidden. In addition, the requires a static public function that takes care of the encapsulation of the initialization and provides a global access point. In the implementation process The employer must ensure that each class is responsible for monitoring that no allow more than one instance.
Diagram or Implementation
Figure 2: UML Diagram Singleton Pattern
Figure 2 explains the behaviour of the pattern by means of a sequence diagram.
- Client class requests the instance from the Singleton class by means of the static method obtainInstance().
- The Singleton class will validate if the instance was already created before, if not then a new one is created.
- The instance created in the previous step is returned or the existing instance is returned in another case.
Study Cases
Printer System
Figure 3: UML Diagram Printer System
Figure 4: UML Diagram Printer System
Bank System
Figure 5: UML Diagram Bank System
Figure 6: UML Diagram Bank System
Implementations of the singleton pattern:
class SingletonMeta(type):
"""
The Singleton class can be implemented in different ways in Python. Some
possible methods include: base class, decorator, metaclass. We will use the
metaclass because it is best suited for this purpose.
"""
_instances = {}
def __call__(cls, *args, **kwargs):
"""
Possible changes to the value of the `__init__` argument do not affect
the returned instance.
"""
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]
class Singleton(metaclass=SingletonMeta):
def some_business_logic(self):
"""
Finally, any singleton should define some business logic, which can be
executed on its instance.
"""
# ...
if __name__ == "__main__":
# The client code.
s1 = Singleton()
s2 = Singleton()
if id(s1) == id(s2):
print("Singleton works, both variables contain the same instance.")
else:
print("Singleton failed, variables contain different instances.")
namespace RefactoringGuru\Singleton\Conceptual;
/**
* The Singleton class defines the `GetInstance` method that serves as an
* alternative to constructor and lets clients access the same instance of this
* class over and over.
*/
class Singleton
{
/**
* The Singleton's instance is stored in a static field. This field is an
* array, because we'll allow our Singleton to have subclasses. Each item in
* this array will be an instance of a specific Singleton's subclass. You'll
* see how this works in a moment.
*/
private static $instances = [];
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
protected function __construct() { }
/**
* Singletons should not be cloneable.
*/
protected function __clone() { }
/**
* Singletons should not be restorable from strings.
*/
public function __wakeup()
{
throw new \Exception("Cannot unserialize a singleton.");
}
/**
* This is the static method that controls the access to the singleton
* instance. On the first run, it creates a singleton object and places it
* into the static field. On subsequent runs, it returns the client existing
* object stored in the static field.
*
* This implementation lets you subclass the Singleton class while keeping
* just one instance of each subclass around.
*/
public static function getInstance(): Singleton
{
$cls = static::class;
if (!isset(self::$instances[$cls])) {
self::$instances[$cls] = new static();
}
return self::$instances[$cls];
}
/**
* Finally, any singleton should define some business logic, which can be
* executed on its instance.
*/
public function someBusinessLogic()
{
// ...
}
}
/**
* The client code.
*/
function clientCode()
{
$s1 = Singleton::getInstance();
$s2 = Singleton::getInstance();
if ($s1 === $s2) {
echo "Singleton works, both variables contain the same instance.";
} else {
echo "Singleton failed, variables contain different instances.";
}
}
clientCode();
package refactoring_guru.singleton.example.non_thread_safe;
public final class Singleton {
private static Singleton instance;
public String value;
private Singleton(String value) {
// The following code emulates slow initialization.
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
this.value = value;
}
public static Singleton getInstance(String value) {
if (instance == null) {
instance = new Singleton(value);
}
return instance;
}
}