Search code examples
javaspringsingletondependency-inversion

I can't understand tha "Singleton pattern violates DIP."


I learned that In singleton pattern, the client depends on the concrete class in the dependency relationship. So singleton pattern violates DIP.

And in the lecture i'm listening (it's spring(java) lecture), teacher showed this code

public class SingletonService {

    private static final SingletonService instance = new SingletonService();
    
    //method that brings instant
    public static SingletonService getInstance() {
        return instance;
    }
    
    // prevent constructor
    private SingletonService() {
    }
}

and I understood this code.

Teacher told "because it uses getInstance() method, it depends on the concrete class"

but I can't understand this.

somebody help me

I'm no expecting something, I just wanna know why singleton violates DIP.

And I tried some example singleton codes, but still I don't know why singleton makes the client depends on the concrete class in the dependency relationship.


Solution

  • The Dependency Inversion Principle (DIP) promotes writing code that relies on abstractions (general concepts) rather than specific implementations (concrete classes). This makes code more flexible and easier to maintain.

    Consider the following example using the Singleton pattern:

    public class Client {
        public void doSomething() {
            SingletonService service = SingletonService.getInstance();
            service.performAction();
        }
    }
    

    In this example, the Client class is tightly coupled to the SingletonService class, violating the DIP. The DIP suggests that the code should instead depend on abstractions:

    public class Client {
        private final SomeInterfaceService service;
    
        public Client(SomeInterfaceService service) {
            this.service = service;
        }
    
        public void doSomething() {
            service.performAction();
        }
    }
    

    In this case, the Client class depends on the SomeInterfaceService interface, not the concrete SingletonService class. This kind of looser coupling is beneficial in several ways.

    For example, if you want to use different implementations of SomeInterfaceService, you can achieve this easily without modifying the Client class:

    public class Main {
        public static void main(String[] args) {
            SomeInterfaceService serviceA = new ServiceA();
            Client client = new Client(serviceA);
            client.doSomething();
        }
    }
    

    If you change serviceA to serviceB, you do not need to modify the Client class:

    public class Main {
        public static void main(String[] args) {
            SomeInterfaceService serviceB = new ServiceB();
            Client client = new Client(serviceB);
            client.doSomething();
        }
    }
    

    By adhering to the Dependency Inversion Principle, you achieve:

    • Loose Coupling: The Client class depends on abstractions rather than concrete implementations, making the code more flexible and maintainable.
    • Improved Testability: You can easily mock SomeInterfaceService in unit tests.
    • Flexibility: You can switch between different implementations of SomeInterfaceService without changing the client code.