Open In App

private vs private-final injection of dependency

Last Updated : 05 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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




// 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

  • Dependency is a private field of type Dependency in the PrivateInjectionExample class. Dependency injection will be shown using this field.
  • It has a setter method called setDependency that lets you set the dependency field using a dependency class object.
  • The business logic of the class is implemented in the performOperation function. It uses the Dependency class’s getData function to display the data and determines if the dependency is set. It produces an error message if the dependency is not set.
  • The program’s entrance point is the principal technique. It first creates an instance of the PrivateInjectionExample class (example), an instance of the dependency class (myDependency), sets the dependency, and then executes the action.

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




//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:

  • Dependency of type Dependency is a private-final field in the PrivateFinalInjectionExample class. Once a dependence is established in the constructor, the private final modifier makes sure that it cannot be altered.
  • For private-final injection, it has a constructor called PrivateFinalInjectionExample(Dependency dependency). The constructor initialises the dependence.
  • The business logic of the class is implemented in the performOperation function. It uses the Dependency class’s getData function to display the data and determines if the dependency is set. It produces an error message if the dependence is not set.
  • The program’s entrance point is the principal technique. After setting the dependent in the constructor and creating instances of the dependent and PrivateFinalInjectionExample classes (myDependency and example, respectively), it executes the procedure.

Implementation:

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

Comparing the Approaches

Encapsulation

  • Private Injection: May break encapsulation by permitting runtime modifications to the injected dependency.
  • Private-Final Injection: Encourages encapsulation by guaranteeing that the injected dependency doesn’t change.

Immutability

  • Immutability is not guaranteed by private injection since the reliance is changeable.
  • Immutability is guaranteed via private-final injection, which also improves thread safety and may have performance advantages.

Step by Step Illustration

Private Injection Example

  • Make a class that includes a private field.
  • Setter methods should be implemented to inject the dependency.
  • Change the dependence during runtime and show how to do it.

Private-Final Injection Example

  • Make sure that your class has a private-final field.
  • To inject the dependency, use a constructor.
  • Emphasize the idea of immutability.

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.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads