Does using Service interface in Spring Boot REST Controller represent Dependency Inversion principle?

102 views Asked by At

I'm learning about Dependency Inversion principle in Java, and the definition is:

  1. High-level modules should not depend upon low-level modules; they should depend on abstractions. 2) Abstractions should not depend upon details; details should depend upon abstractions.

And I have a piece of code from a REST API implementation and I want to know if this code represents an example of Dependency Inversion.

Rest Controller:

@RestController
@RequestMapping("/api")
public class EmployeeRestController {
    private EmployeeService employeeService;
    
    public EmployeeRestController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @GetMapping("/employees")
    public List<Employee> findAll() {
        return employeeService.findAll();
    }
...
}

Service Interface:

public interface EmployeeService {
    public List<Employee> findAll();
    
    public Employee findById(int theId);
    
...
}

Service Implementation:

@Service
public class EmployeeServiceImpl implements EmployeeService {
    private EmployeeDAO employeeDAO;

    @Autowired
    public EmployeeServiceImpl(EmployeeDAO employeeDAO) {
        this.employeeDAO = employeeDAO;
    }

    @Override
    @Transactional
    public List<Employee> findAll() {
        return employeeDAO.findAll();
    }
    ...
}

Entity:

@Entity
@Table(name="employee")
public class Employee {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private int id;
    
    @Column(name="first_name")
    private String firstName;
    ...
}

So, I want to ask you if this code represents an example of Dependency Inversion principle, or it represents just the Dependency Injection design pattern?

For me, the controller class represents the high-level module and the service implementation represents the low-level module, and the high-level module depends on the abstractions because there is the EmployeeService interface used in the EmployeeRestController. And also the low-level module depends on abstractions because EmployeeServiceImpl implements EmployeeService. Is this true?

But what is the difference between Dependency Inversion and Dependency Injection in this example? The fact that I declare private EmployeeService employeeService; in the EmployeeRestController represents Dependency Inversion. So if I declare directly the class EmployeeServiceImpl in the EmployeeRestController I don't have Dependency Inversion principle. And the fact that I inject the implementation of the EmployeeService at runtime in the constructor represents Dependency Injection. Is that correctly?

But in the Service interface I'm using the Employee which is a class. So it means that in that case abstraction depends on details. So the second part of the Dependency Inversion principle is not satisfied. And because of that I don't have Dependency Inversion. Please tell me if it's true? Thank you!

2

There are 2 answers

3
Black Bear On BEST ANSWER

Just Draw on the paper and you will get the idea

1.lets say you put the controller and Service in the package A, and you put the ServiceImpl in package B, in this case package B depends on package A, since service Impl refers to Service, and Service is in package A.

Using injection you are able to have service impl object in the controller but notice that controller does not know about impl(A does not know about B)

2.if there was no injection, the only way the controller could have service impl object is by referring to the impl class(in this case A knows about B which is bad )

so if we say that Package A is abstraction and package B is detail ,in the 1 point B depends on A (which is good)which means that detail depends on abstraction

But in the second point, A knows about B which means Abstraction depends on detail(not good)

So we achieved dependency inversion using injection

2
Alan Krueger On

Related to the terminology and how the concepts interact, you might want to read https://stackoverflow.com/a/3912604/7708

Related to the Employee class, I think you may be overthinking it. You could conceivably make Employee an interface (an abstraction), putting its implementation into an EmployeeImpl class. However, this is probably too much abstraction. It's just a data container and doesn't actually implement any logic to speak of, so there's no need to add that level of indirection to abstract away behavior. The annotations it contains declare how it should interact with a data source but don't actually implement that behavior, relying on the framework to generate that logic for you.