Singleton Design Pattern
Video Lecture
Section | Video Links |
---|---|
Singleton Overview | |
Singleton Use Case | |
Python Dictionary |
Overview
Sometimes you need an object in an application where there is only one instance.
You don't want there to be many versions, for example, you have a game with a score, and you want to adjust it. You may have accidentally created several instances of the class holding the score object. Or, you may be opening a database connection, there is no need to create many, when you can use the existing one that is already in memory. You may want a logging component, and you want to ensure all classes use the same instance. So, every class could declare their own logger component, but behind the scenes, they all point to the same memory address (ID).
By creating a class and following the Singleton pattern, you can enforce that even if any number of instances were created, they will still refer to the original class.
The Singleton can be accessible globally, but it is not a global variable. It is a class that can be instanced at any time, but after it is first instanced, any new instances will point to the same instance as the first.
For a class to behave as a Singleton, it should not contain any references to self
but use static variables, static methods and/or class methods.
Singleton UML Diagram
Source Code
In the source code, I override the classes __new__
method to return a reference to itself. This then makes the __init__
method irrelevant.
When running the example, experiment with commenting out the __new__
method, and you will see that the IDs of the instances no longer point to the same memory location of the class, but to new memory identifiers instead. The class is no longer a Singleton.
./singleton/singleton_concept.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Output
python ./singleton/singleton_concept.py
id(Singleton) = 2164775087968
id(OBJECT1) = 2164775087968
id(OBJECT2) = 2164775087968
id(OBJECT3) = 2164775087968
Notes
Variables declared at class level are static variables that can be accessed directly using the class name without the class needing to be instantiated first.
cls is a reference to the class
self is a reference to the instance of the class
_new_ gets called before _init_,
_new_ has access to class level variables
_init_ references self that is created when the class is instantiated
By using _new_, and returning a reference to cls, we can force the class to act as a singleton. For a class to act as a singleton, it should not contain any references to self.
SBCODE Editor
Singleton Use Case
In the example, there are three games created. They are all independent instances created from their own class, but they all share the same leaderboard. The leaderboard is a singleton.
It doesn't matter how the Games where created, or how they reference the leaderboard, it is always a singleton.
Each game independently adds a winner, and all games can read the altered leaderboard regardless of which game updated it.
Example UML Diagram
Source Code
./singleton/client.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
./singleton/game1.py
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
./singleton/game2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
./singleton/game3.py
1 2 3 4 5 6 |
|
./singleton/leaderboard.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
./singleton/interface_game.py
1 2 3 4 5 6 7 8 9 10 11 |
|
Output
python ./singleton/client.py
-----------Leaderboard-----------
| 1 | Emmy |
| 2 | Cosmo |
| 3 | Sean |
-----------Leaderboard-----------
| 1 | Emmy |
| 2 | Cosmo |
| 3 | Sean |
-----------Leaderboard-----------
| 1 | Emmy |
| 2 | Cosmo |
| 3 | Sean |
SBCODE Editor
New Coding Concepts
Python Dictionary
In the file ./singleton/leaderboard.py,
4 5 |
|
The {}
is indicating a Python Dictionary.
A Dictionary can be instantiated using the curly braces {}
or dict()
The Dictionary is similar to a List, except that the items are key:value
pairs.
The Dictionary can store multiple key:value
pairs, they can be changed, can be added and removed, can be re-ordered, can be pre-filled with key:value
pairs when instantiated and is very flexible.
Since Python 3.7, dictionaries are ordered in the same way that they are created.
The keys of the dictionary are unique.
You can refer to the dictionary items by key, which will return the value.
1 2 3 4 |
|
You can change the value at a key,
1 2 3 4 5 |
|
You can add new key:value
pairs, and remove them by using the key.
1 2 3 4 5 6 7 8 9 |
|
Furthermore, you can order a dictionary alphabetically by key
1 2 3 4 5 6 |
|
Summary
- To be a Singleton, there must only be one copy of the Singleton, no matter how many times, or in which class it was instantiated.
- You want the attributes or methods to be globally accessible across your application, so that other classes may be able to use the Singleton.
- You can use Singletons in other classes, as I did with the leaderboard, and they will all use the same Singleton regardless.
- You want controlled access to a sole instance.
- For a class to act as a singleton, it should not contain any references to
self
.