Introduction Singleton Design Pattern
Singleton design pattern is categorized under creational design patterns.
The Singleton Pattern guarantees a class has one instance only and a global point of access to it is provided by that class. Anytime multiple classes or clients request for that class, they get the same instance of the class.
The Singleton pattern solves two problems at the same time:
1) Ensure that a class has just a single instance.
Why would anyone want to control how many instances a class has? The most common reason for this is to control access to some shared resource for example, a database or a file.
Here’s how it works: imagine that you created an object, but after a while decided to create a new one. Instead of receiving a fresh object, you’ll get the one you already created.
Note that this behavior is impossible to implement with a regular constructor since a constructor call must always return a new object by design.
2) Provide a global access point to that instance.
Remember those global variables that you used to store some essential objects? While they’re very handy, they’re also very unsafe since any code can potentially overwrite the contents of those variables and crash the app.
Just like a global variable, the Singleton pattern lets you access some object from anywhere in the program. However, it also protects that instance from being overwritten by other code.
There’s another side to this problem: you don’t want the code that solves problem #1 to be scattered all over your program. It’s much better to have it within one class, especially if the rest of your code already depends on it.
Nowadays, the Singleton pattern has become so popular that people may call something a singleton even if it solves just one of the listed problems.
Use case of Singleton design pattern
But before moving into the example, you need to know that there are two common steps in every Singleton implementation.
- First step is to make the default constructor private, so it can prevent other objects from using the new operator with the Singleton class.
- Then implement a static creation method that acts as a constructor.This method calls the private constructor to create an object and saves it in a static field. So, whenever this method gets called, it will return the object.
Note: The most common use case for applying Singleton design pattern is when dealing with databases.
Example 01: Classic Implementation
It's quite easy to implement this pattern. The following code snippet shows how a Singleton is created.
public class Singleton {
private static Singleton INSTANCE = null;
// other instance variables can be here
private Singleton() {};
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return(INSTANCE);
}
}
In the code above, we have a static variable INSTANCE to hold an instance of the class. We also made the constructor private because we want to enforce noninstantiability—the class can only instantiate itself. The method getInstance() guarantees that the class is instantiated, if it has not been, and that it's returned to the caller.
Example 02:Creating a Single Instance of Retrofit
In an Android app, you'll need a single global instance of a Retrofit object so that other parts of an app can use it to execute a network request without the need to create an instance every single time we need it.
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitClient {
private static Retrofit retrofit = null;
private RetrofitClient() {}
public static Retrofit getClient(String baseUrl) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
So anytime client A calls RetrofitClient.getClient(), it creates the instance if it has not been created already, and then when client B calls this method, it checks if the Retrofit instance already exists. If so, it returns the instance to client B instead of creating a new one.
Note : The main problem with above method is that it is not thread safe.
To solve the problem, it is better to implement the following method
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitClient {
private static volatile Retrofit retrofit = null;
private RetrofitClient() {}
public static Retrofit getClient(String baseUrl) {
if (retrofit==null) {
synchronized (RetrofitClient.class) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
}
return retrofit;
}
}
We have declared the retrofit volatile which ensures that multiple threads offer the retrofit variable correctly when it is being initialized to RetrofitClient instance.
Top comments (0)