Open In App

private vs private-final injection of dependency

Dependency Injection (DI) is essential for improving code modularity, maintainability, and testability in the context of sophisticated Java programming. Choosing between private and private-final injection for dependencies is a typical DI concern. We will examine the distinctions between these two strategies in this post, as well as their applications and ramifications.

Prerequisites

You should be acquainted with advanced Java concepts and have a solid knowledge of Dependency Injection in Java before moving on to private and private-final injection. It’s also helpful to understand the fundamentals of object-oriented programming (OPP) and how to use frameworks like Spring or Guice.



Dependency Injection

A design technique known as dependency injection involves injecting system components into a class rather than having the class establish or manage its dependencies. By attaining loose coupling, this contributes to the modularity and maintainability of the code.

Private Injection

In private injection, constructor injection or setter methods are used to inject dependencies into a class’s private variables. Although this method allows for flexibility in modifying dependencies during runtime, encapsulation problems may arise.



PrivateInjectionExample.java:




// Java program to demonstrate Private Injection
class Dependency {
    private String data;
  
    public Dependency(String data) {
        this.data = data;
    }
  
    public String getData() {
        return data;
    }
  
}
  
public class PrivateInjectionExample {
    private Dependency dependency;
  
    // Setter method for private injection
    public void setDependency(Dependency dependency) {
        this.dependency = dependency;
    }
  
    // Business logic using the injected dependency
    public void performOperation() {
        // Use the dependency
        if (dependency != null) {
            System.out.println("Performing operation with data: " + dependency.getData());
        } else {
            System.out.println("Dependency not set. Cannot perform operation.");
        }
    }
  
    // Main class for demonstration
    public static void main(String[] args) {
        // Create an instance of Dependency
        Dependency myDependency = new Dependency("Hello, Dependency!");
  
        // Create an instance of PrivateInjectionExample
        PrivateInjectionExample example = new PrivateInjectionExample();
  
        // Set the dependency using the setter method
        example.setDependency(myDependency);
  
        // Perform the operation
        example.performOperation();
    }
}

Output
Performing operation with data: Hello, Dependency!



Explanation:

Dependency Class: A private data field, a constructor for initializing the data field, and a getter function (getData) for retrieving the value of data are all specified in the Dependency class.

PrivateInjectionExample Class

Implementation:

This program creates the dependency and does the operation, outputting “Performing operation with data: Hello, Dependency!” after it runs.

Private-Final Injection

A version known as “private-final injection” designates the injected fields as final. This provides immutability and the inability to modify the dependence after it has been established. This method may improve code optimisation and increase thread safety.

PrivateFinalInjectionExample.java:




//Java program to demonstrate Private Final Injection
class Dependency {
    private String data;
  
    public Dependency(String data) { this.data = data; }
  
    public String getData() { return data; }
}
  
public class PrivateFinalInjectionExample {
    private final Dependency dependency;
  
    // Constructor for private-final injection
    public PrivateFinalInjectionExample(
        Dependency dependency)
    {
        this.dependency = dependency;
    }
  
    // Business logic using the injected dependency
    public void performOperation()
    {
        // Use the dependency
        if (dependency != null) {
            System.out.println(
                "Performing operation with data: "
                + dependency.getData());
        }
        else {
            System.out.println(
                "Dependency not set. Cannot perform operation.");
        }
    }
  
    // Main class for demonstration
    public static void main(String[] args)
    {
        // Create an instance of Dependency
        Dependency myDependency
            = new Dependency("Hello, Dependency!");
  
        // Create an instance of
        // PrivateFinalInjectionExample
        PrivateFinalInjectionExample example
            = new PrivateFinalInjectionExample(
                myDependency);
  
        // Perform the operation
        example.performOperation();
    }
}

Output
Performing operation with data: Hello, Dependency!




Explanation:

Dependency Class: Like in the previous example, the Dependency class is constructed with a getter function (getData) to obtain the value of data, a constructor to initialise the data field, and a private data field.

PrivateFinalInjectionExample Class:

Implementation:

This program creates the dependence and does the operation, outputting “Performing operation with data: Hello, Dependency!” after it runs.

Comparing the Approaches

Encapsulation

Immutability

Step by Step Illustration

Private Injection Example

Private-Final Injection Example

Conclusion

In conclusion, there are trade-offs between flexibility and encapsulation when deciding between private and private-final injection in Dependency Injection. Making the best decision will be aided by your comprehension of the particular needs of your application and the required degree of immutability. Each strategy has advantages, and the one you choose should be in line with the overall project objectives and design principles.


Article Tags :