Photo by Yuri Yuhara on Pexels

DESIGN PATTERNS IN JAVA SERIES

Design Patterns in Java/Android — Singleton

Explanations, Caveats, Examples from Android Framework & Java Libraries, Writing our own Singleton

Published in
5 min readMar 13, 2022

--

This series on Software Design Patterns will introduce some common design patterns that we use in app development.

  1. Singleton ← we are here
  2. Builder
  3. Factory
  4. Prototype
  5. Adapter
  6. Facade
  7. Observer
  8. Command

Here, we will take examples of existing design patterns in Android framework & Java Libraries and also write our own patterns in Java.

Introduction to Design Patterns

Software Design Patterns are time-tested, reusable solutions to recurring software problems. They define a common language that helps our team communicate more efficiently.

Design patterns usually deals with objects. The patterns differ by their complexity, reusability, purpose and scale of application in the system. All patterns an be categorized mainly into 3 categories based on their purpose:

  • Creational patterns: How the objects are created.
    Eg. Singleton pattern, Builder pattern, Factory pattern
  • Structural patterns: How the objects are composed (assembling objects into larger structures).
    Eg. Adapter pattern, Facade pattern, Decorator pattern
  • Behavioral patterns: How the objects coordinate (communication and assignment of responsibilities between objects).
    Eg. Observer pattern, Strategy pattern, Command pattern

Singleton Design Pattern

The Singleton is the most common design pattern. It is a simple creational design pattern. This pattern ensures a class has one instance at most and the class itself provides a global point of access. If one/many clients request for that class, they get the same instance of the class. This singleton class can instantiate itself, or we can delegate the object creation to a Factory class (another creational pattern, we will learn in future article).

All references pointing to the same object in Singleton Pattern (Image from refactoring.guru)

Examples of Singleton from Android Framework & Java Libraries

NOTE: You may skip to “Writing our own Singleton in Java” if you know only Java, but not Android

In a standard Android app, many times we need only one global instance for classes (whether we are using that object directly or passing it to another class). We use Singleton Pattern at the time. Examples of Singleton patterns in Android Framework and Libraries are: SharedPreferences, most Firebase APIs, OkHttpClient, Database connection, Retrofit, Gson, etc.

Android SharedPreferences

A SharedPreferences object points to a file containing key-value pairs and provides simple methods to read and write them. For any particular set of preferences, there is a single instance of this class that all clients share.

  • SharedPreferences is a Singleton object, it opens the file for shared preferences only when we call getSharedPreferences first time. So, even when we get many references of SharedPreferences, there is no issue.
  • As SharedPreferences is a Singleton object, if we modify any of its references, the data gets modified for all of them. This happens because there is only one instance of any Singleton class.

Firebase Analytics

Firebase Analytics (closely related to Google Analytics) provides free, unlimited reporting on hundreds of distinct events. The FirebaseAnalytics (top level of Firebase Analytics) is a singleton that provides methods for logging events and setting user properties.

  • FirebaseAnalytics.getInstance() returns a SingletonFirebaseAnalytics interface. So, even when we get many references of FirebaseAnalytics, there is no issue.

OkHttpClient

OkHttp is an HTTP client for Android and Java applications.

  • OkHttpClient shown below is a Singleton

Writing our own Singleton in Java

Let us create our own Singleton Pattern now.

The singleton pattern restricts the instantiation of a class to one object. Sometimes we need to have such class. Let’s see various ways of implementing such a class. If we have a good understanding of static class variables and access modifiers, achieving this should not be a difficult task.

1. Basic Lazy/Late Initialization Singleton

Here, we have declared getInstance() static, so we can call it without instantiating the class. When we call getInstance() for the first time, it creates a new singleton object and but after that it simply returns the same object. The Singleton instance is not created till we call getInstance() method. That is why it is called Lazy initialization.
The primary issue in above method is that this design is not thread safe. Two threads calling it simultaneously for the first time can create 2 objects for the Singleton.

2. Synchronized Lazy/Late Initialization Singleton

By using synchronized, we are making sure that only one thread can execute getInstance() at a time. So, the issue in the “design 1” above is resolved. Thus, this design is thread safe.
Only disadvantage in this design is that since synchronized is used every time while creating a singleton object, and it is an expensive process, so it may decrease the performance of our program slightly.

If performance of getInstance() is critical (it is not called huge number of times) in our app, this is a decent solution.

3. Eager/Early Initialization Singleton

We are creating instance of Singleton in static initializer. The Singleton instance is created without the need to call getInstance() method. That is why it is called Early initialization. In this design, the JVM executes static initializer when the class is loaded, so this design is thread safe.

If our Singleton class is light (since class is created in the beginning) or it is used throughout the execution of our app, this is a decent solution.

4. Double Checked Locking Singleton

Here, we have declared the Singleton instance as volatile because we want to ensure that multiple threads offer the instance variable correctly when it is being initialized. We an also use final instead of volatile, that will also serve the purpose.

  • final: we can only write to final once and that is visible to other threads
  • volatile: any writes to the volatile field will be visible from other threads, so when we write to field, that is visible to other threads that try to read field

The design in above code provides huge improvement by reducing the overhead of calling the synchronized method every time. This design is thread safe and the best among all designs presented here.

-> Running our Singleton Patterns

This code can be used to run all the 4 methods of Singleton given above.

This article is supposed to serve as a beginner’s guide for the above design pattern.

Give a clap if you liked the article or a leave a comment for any suggestion/discussion/dispute. Thank you!

--

--

Android Developer (Kotlin, Java, OOPS, Data Structures, Algorithms, Design Patterns) github.com/Suryakant-Bharti