Why Singleton is Anti Pattern in Java? Example

There was a time when the Singleton pattern was the darling pattern of many developers. It's a unique feature to keep certain services available globally, makes it very useful in all kinds of applications. It was also one of the most used design patterns among Java developers. I think the main reason for the Singleton pattern's popularity of designing the application is that there is always one instance of the most important service like Manager and Data Access classes. Still, with the adoption of Dependency injection, Singleton slowly faded away, and now it's considered an anti-pattern in Java applications. 

In this article, you'll learn why Singleton is anti-pattern now and what happens when you use the Singleton pattern in Java. Along the way, you will also learn about dependency injection, a better alternative to the Singleton pattern, and several benefits it offers. 

Comes with Dependency injection, TDD, and Unit testing, and slowly programmer started realizing how to test Singleton was tough to mock. All the code which was calling Singleton.getInstance() was also difficult to test because instead of asking, they are querying their dependency. Dependency injection becomes


An Example of why Singleton is Bad or Anti Pattern?

Here is an example of why the Singleton pattern is not good for modern Java development. You will see that testing a Singleton is almost impossible by writing unit tests.

package patterns;

/*
 * A class which uses Singleton class, MailService
 */
public class MailServiceClient {

    /*
     * This method is hard to test because it uses Singleton class.
     */
    public void sendPaymentReminder() {
        Singleton.getInstance().mail();
    }
}

/*
 * An eager implementation of Singleton pattern in Java.
 */
class MailService {

    private static MailService INSTANCE = new MailService();

    private MailService() {
        throw new UnsupportedOperationException("Singleton 
                   INSTANCE creation is not allowed");
    }

    public static MailService getInstance() {
        return INSTANCE;
    }

    public void mail() {
        System.out.println("Mail sent to external party");
    }
}


Testing Singleton in Java

Now, let's try to write a test for Singleton class and find out how hard or easy it is:
package patterns;
import static org.junit.Assert.*;
import org.junit.Test;

public class SingletonClientTest {

 @Test
 public void sendPaymentReminder() {
  // $*@&#$ (how do I mock the Singleton
 }


Better Alternative of Singleton Pattern

The alternative of Singleton using Interface and Dependency Injection

public interface MailService {
    public void mail();
}

public class MailServiceImpl implements MailService{
    public void mail(){
       // send mail to external party
    }

}

Now let's rewrite the SingletonClient class, which make use of the Singleton pattern using Dependency injection :

public class PaymentReminder{
   private final MailService _mailService;

   public PaymentReminder(MailService singleton){
      this._mailService = singleton;
   }

   public void sendPaymentReminder(){
       _mailService.mail(); // mail sent to external party
   }
}
Now let's write a unit test to test our PaymentRemider class, this time. We don't need to mock Singleton. Instead, we will use dependency injection to inject a MockMailService, which doesn't send emails to the internal party.

public class TestPaymentReminder{
   MailService mock = new MockMailService();
   PaymentReminder pr = new PaymentReminder(mock);

   pr.sendPaymentReminder(); // mail will go to local INBOX

}

So, you can see that Dependency Injection offers a better alternative to Singleton Pattern in Java. 

Why Singleton is Anti Pattern in Java? Example



7 Reasons Why Singleton is Anti Pattern

Now, let's revise all the reasons why Singleton is Anti-pattern now.

1. Hard to test
2. Hidden Coupling
3. Many instances of Singleton
4. Hard to Evaluate
5. Hart to SubClass
6. Better Alternatives available using Dependency Injection
7. Initialization order


What have we learned from Singleton?

Interfaces are Dependency injection provides a better alternative of Singleton:
- Reduce hidden coupling
- Allow testability
- Allow subclassing
- Make construction and use flexible

If you just need one instance, control by configuration, not by pattern, and this can be easily achieved by using modern-day DI and IOC frameworks like Spring or Google Guice. In the worst case, you can even do it by hand using setter injection.


Other Java Design Patterns tutorials you may like
  • 5 Free Courses to learn Object Oriented Programming (courses)
  • How to implement Command Pattern in Java? (example)
  • Difference between Factory and Dependency Injection Pattern? (answer)
  • 7 Best Courses to learn Design Pattern in Java (courses)
  • How to create thread-safe Singleton in Java (example)
  • 7 Best Books to learn the Design Pattern in Java? (books)
  • How to implement the Strategy Design Pattern in Java? (example)
  • Difference between Factory and AbstractFactory Pattern? (example)
  • How to implement Composite Pattern in Java? (example)
  • 18 Java Design Pattern Interview Questions with Answers (list)
  • How to design a Vending Machine in Java? (questions)
  • 20 System Design Interview Questions (list)
  • Difference between State and Strategy Design Pattern in Java? (answer)
  • Top 5 Courses to learn Design Patterns in Java (courses)
  • 5 Free Courses to learn Data Structure and Algorithms (courses)

Thanks a lot for reading this article so far. If you like this Java design pattern tutorial, then please share it with your friends and colleagues. If you have any questions or feedback, then please drop a note. You can also see these design pattern courses to learn more. 

No comments :

Post a Comment