Design Patterns: Introduction with Singletons
This is the first instalment of a series about design patterns in software development. Each post will discuss a new design pattern and will try to explain possible situations in which they could save a lot of hassle.
This is not about UX design, nothing graphical really, but more about the patterns in software design. Structural, creational and behavioural patterns. Applying design patterns in software design might actually create a few benefits for a development team:
- Code / software will become easily maintainable.
- There will be high re-usability.
- Due to abstractions, code will be more readable.
- Because of these benefits, introducting new developers to the team will be easy.
- Creational, behavioural and structural aspects of software can be more easily explainable to product owners and even stakeholders.
This series is supposed to be a basis for future blog posts about software engineering or architecture.
Object oriented programming
Design patterns discussed in this series require an object oriented programming language, therefore I shall be using TypeScript or Babel in example code. You can apply design patterns anywhere there is classes, abstraction and interfaces.
A few types of relations in OO are important as well: - Generalisation - Association - Aggregation / composition
Unified Modeling Language
Another requirement in this series will be a slight understanding of UML-diagrams. I will be using these (simple) diagrams to display a schematic of interfaces, classes and their relations.
The Singleton Pattern
Finally, to business. The Singleton pattern is one of the less complex patterns in the range of creational patterns. Its purpose is only allowing one instance of a class, meaning there should be only one object of that class ever. These singleton classes usually have a private static property of the class type, a static public method called GetInstance and a private constructor.
Before we get into it more, a UML diagram of a typical singleton pattern class:
The important things to note:
- The constructor is private in the ApplicationSettings class, so it can only be called from within a method in the ApplicationSettings class.
- There is a static private property called instance, which holds the one and only instance to the ApplicationSettings class in existence.
- There is a static method called GetInstance(), and this is where the logic of the singleton pattern is enforced. When executed, it checks if the static instance property is null. If so, it instantiates the class and puts the reference to the object in that instance property. When GetInstance() is done executing, it returns that instance to the caller. GetInstance() is allowed to construct an object.
The method of applying this pattern in this situation is called lazy initialization. This means that the instance is only initiated when GetInstance() is called. On mobile devices or in embedded programming, this has great advantages, because it saves the overhead memory.
Why would you ever create a class which can only produce one object, why not something static? Good question.
Aside from the lazy loading previously mentioned, there are a few more advantages.
The best reason to me is that you don't pollute the containing namespace. The only thing polluting the containing namespace is the class itself.
You provide certain logic and information (such as the ApplicationSettings class) with its own environment to store everything. You then can easily add access modifiers to methods and properties, and hide logic and data that is not important outside of the class.
For example, you want to provide read only access to certain properties of the class via public getters, but prevent other code from setting those properties to new values.
Another good reason is making some unique data and logic available throughout the whole containing namespace, or globally if the class was defined as public. For example, a property in the ApplicationSettings instance can be accessed anywhere by simple calling
Re-usability and modularity
You can easily use this complete ApplicationSettings class in any future package by adding it to a new project. Design patterns are meant to be re-usable. It would be easy to have ApplicationSettings, PhoneSettings and UserSettings singleton classes that all implement an ISettings interface to allow for modularity.
Here's a schematic showing a singleton structure that is modular. One could simply talk to
ISettings objects in this case.
Example in TypeScript
Here's a simple example in TypeScript that animates a little box. The idea in this example is that, in most 2D rendering cases, you output to one view and only have one loop ticking at 60 FPS.
Check out this pen.
Example real-life applications
- Global settings objects (iOS and Android developers will relate)
- Loggers (debug loggers don't need multiple instances)
- DirectX / OpenGL rendering systems
- General hardware access systems
- Database connections
This might have been a long read, but I sure hope that this is a good start for a series about design patterns. If you have any feedback, let me know in the comments, I'll make sure to make these posts as educational as I can. Also please let me know about errors in the text.
The next pattern I will discuss is the Strategy pattern. After that, I will take a look at the Observer, Decorator (tricky one!) and then the Command pattern (quite useful one!). After that, I will see which one I'll write about. If you have suggestions, let me know!