Every pattern strives for perfection?
Almost always, creating software for large businesses is challenging. Even though we have many patterns and frameworks at our disposal that can make this process easier, we still need to learn how to use these components efficiently. Different approaches to the problem are possible, but the trick is to know when to use each one for a specific set of parameters.
It’s extremely difficult to find a strategy that works in every situation. I will try to give some examples of how I have used them in my work on relevant projects through a series of blogs that I will write. Normally, I’ll also explain the methodologies. But the actual situation we face every day are far more important than formal methodology. Let’s begin by choosing the Singleton pattern as our first option.
The idea behind a Singleton Pattern is to ensure that a class has only one instance, and then to provide an access point that is available throughout the program. As a result, there should only be one instance of a given class. We can use this instance whenever we need it to prevent the creation of non-essential objects and reduce the overhead associated with memory usage.
One example from real life
A singleton pattern is comparable to a shared resource among multiple family members. Examples of singleton patterns include all household members sharing a single washing machine or all family members sharing a single appliance, such as a refrigerator.
One example from the computer world
When we need to manage a shared resource, we utilize an approach known as the singleton pattern. Consider, for instance, a printer. To prevent competing requests for the same resource from being processed by your application, only one instance of the waiting program should be active. The same example is for a database connection or a file storage system.
The most important aspect of implementation
In this particular case, the constructor is a private method. Therefore, you cannot instantiate in the conventional way using the new keyword, as in the example.
You check if you already have a backup copy of the class in your memory space, ie. that would be the first step you must take before attempting to instantiate the class. In case you do not already own a duplicate, you will need to create one. Otherwise, you’ll just be using a copy that’s already available.
Now we are going to make an example that is at least somewhat applicable to real-world situations, so that you will be able to apply it in a variety of different contexts.Now the question is why should we complicate things? You can simply write your Singleton class as in the following example.
This approach has the potential to succeed in single-threaded environments. But consider working in an environment with multiple threads. Let’s assume that in a system that supports multiple threads, at least two are attempting to use this:
public static Singleton Instance => instance ?? = new Singleton ();
If they discover that the instance has not yet been created, each of them will try to establish a new instance themselves. As a consequence, you may end up with multiple instances of the class.
Are there alternative approaches for modeling Singleton Pattern
There are numerous possible approaches. Each has both positive and negative attributes. I will shortly discuss a strategy known as double-checked locking.
It will be simpler for you to create circumstances where they are actually required if you adopt this strategy. The cost of the locking mechanism is typically quite high, so keep that in mind.
Why multiple instances can be a problem
In the real world, the process of creating an object is considered an expensive operation in the context of memory, CPU, and so on. It is possible that at some point you will need to put a centralized object in order to simplify maintenance. With the help of this you will also be able to provide a global access mechanism.
Also, it is important to note that using the sealed keyword and implementing private constructors can stop the derivation process. This was optional, but it’s always better to make your intent clear. I used it to protect one special case, if you’re tempted to use a derived nested class like below, you won’t be able to.
After this attempt you will get a compiler error.
Ways to create singletons and the trade-offs between them
The biggest problem with the singleton pattern, and why it is therefore a design anti-pattern and not a design pattern, is the assumption that there will only ever be one instance, and this is often broken during the lifetime of the project, and this pattern structures the code in a way that requires a very significant effort to refactor when this assumption is inevitably wrong.
For instance, if a new process instance is started for each incoming HTTP request that needs to be handled, we can assume that our application will only process one HTTP request at a time. The HTTP request object could then be created initially as a singleton.
This assumption, however, turns out to be false if we later change the architecture to use multiple threads to handle numerous requests within a single instance of the application. As a result, significant code rewriting is required to handle this new state.
This and numerous other examples demonstrate the need to ensure code flexibility in the event that the singleness assumption proves to be false and this pattern appears to be less flexible than expected.
The singleton pattern not only makes the code rigid but also makes testing the code very challenging. This is so that constructors or other methods that use the singleton pattern don’t implicitly assume a dependency that the singleton pattern introduces through a side channel.
Even if this side channel can be replaced, the tests are very challenging to comprehend because the need to do so is less obvious. My recommendation is to use this form with caution. GitHub statistics indicate that Singleton is still a very common and well-liked pattern, despite the fact that it should generally be avoided.
The article is originally published at: https://www.admir.live/post/every-pattern-strives-for-perfection