Creational Design Patterns 1 - Singleton Design Pattern
“Design patterns should not be applied indiscriminately. Often they achieve flexibility and variability by introducing additional levels of indirection, and that can complicate a design and/or cost you some performance. A design pattern should only be applied when the flexibility it affords is actually needed.”
― Erich Gamma, Design Patterns: Elements of Reusable Object-Oriented Software
Creational design patterns are used to abstract the process of instantiating objects. They are used in scenarios when a system should not be dependent on how objects are created. One example could be :
a game that lets you build houses. It would not be practical to have one long class that has all the code for making each different type of room and all the items in the room. It would be much better to encapsulate the code for creating the objects in separate ways. There are lots of creational design patterns that could be applied to this game. Creational design patterns become more important as systems become more complex.
There are two main themes that are common to most creational design patterns.
- They encapsulate knowledge about which concrete class the system should use.
- They conceal how objects are created and put together.
# 1- Singleton Design Pattern :
As the name suggest, Singleton pattern restricts the instantiation of a class to only one (single) instance. This means that whenever we have a reference to a singleton object at anywhere inside our codes, it must refer to the same instance .
This is done by :
- having private constructor
- ensuring that we only instantiate the class once.
public class RepositoryPattern{ private static RepositoryPattern repositoryPattern; private RepositoryPattern() { // Do something during construction // eg. initializing other instance variables (if any) } public static RepositoryPattern getInstance() { if (repositoryPattern== null) { repositoryPattern= new RepositoryPattern(); } return repositoryPattern; } ... }
Referring to the code example above, to get the instance of RepositoryPattern class, we simple call the static getInstance() method which will consistently give us the same instance throughout our program .
However, it should be used with precautions as the construction of a singleton class is static (global), allowing access from multiple objects. This global state might be difficult to track.
Benefits of the Singleton Pattern :
In a typical Android app, there are many objects for which we only need one global instance, whether you are using it directly or simply passing it to another class. Examples include OkHttpClient, HttpLoggingInterceptor, Retrofit, Gson, SharedPreferences, the repository class, etc. If we were to instantiate more than one of these types of objects, we'd run into problems like incorrect app behaviour, resource overuse, and other confusing results.
Example: Creating a Single Instance of Retrofit
Retrofit is a popular library to connect a REST web service by translating the API into Java interfaces.
import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class RetrofitClient { private static Retrofit retrofit = null; 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.
Dealing With Multithreading
In the Android system, you can spin off multiple threads to perform different tasks. These threads can end up executing the same code block simultaneously. In the case of the Singleton class above, this could lead to the creation of multiple object instances, which violates the contract of a Singleton. So our Singleton code snippet method getInstance() is not thread safe. We'll now look at ways to make it thread safe.
public class Singleton { private static Singleton INSTANCE = null; // other instance variables can be here private Singleton() {}; public static synchronized Singleton getInstance() { if (INSTANCE == null) { INSTANCE = new Singleton(); } return(INSTANCE); } // other instance methods can follow
}
Solution : By making the method getInstance synchronized
Many Thanks for reading in other articles we will discuss other design patterns .