It is a best practice to refere to the interface because in this way you can always change the actual implementation with no modification on the caller of that interface. Suppose you have a CDI environment like Spring. You can have your ServiceInterface
with multiple implementations, but a controller will never see the actual implementation.
Controller:
@Controller
public class MyController {
@Autowired
private ServiceInterface service;
/*stuff*/
}
ServiceInterface:
public interface ServiceInterface{ /*stuff*/ }
Implementation "A":
@Service
@Profile("A")
@Primary
public class ServiceImplementationA implements ServiceInterface {
/*stuff*/
}
Implementation "B":
@Service
@Profile("B")
public class ServiceImplementationB implements ServiceInterface {
/*stuff*/
}
Spring has its own mechanism for selecting implementations (which are called profiles), but alternatives exists like factories. As long the interface does not change, you can switch between the two service implementation: no variation will be detected by controller class.