1

Let me first describe the situation

I have a component that uses dependency injection through a service locator. In the first scenario (image 1) the component needs a class that implements Interface0, so it just asks for it at the service locator, something like this (in pseudocode):

Inferface0 i0 = serviceLocator.get(Interface0);

single interface and implementation

This first scenario is very simple. Now the second scenario, where the component and service locator stays the same, but now the component needs a class that implements Interface1 and Interface2, like image 2 shows.

multiple interfaces and implementations

The question is, there is needed to create a new interface (let's call it Interface4) that implements Interface1 and Interface2 so I can ask for it like following?

Inferface4 i4 = serviceLocator.get(Interface4);

And then, if later the component needs an implementation of Interface2 and Interface3 then a creation of Interface5 would be needed? What is the best approach to handle this interfaces?

5
  • Side note: service locator often considered anti-pattern, so there is really no need for you to mention that in the question - there is no difference between asking this question for service locator or constructor ingestion. While it was not (yet?) case here, showing code/concepts that are not needed for the question but controversial (or outright frowned upon like SQL injection sample code or parsing HTML with regex) - may derail questions by flood of comments on such concepts instead of the main topic. Mar 28, 2023 at 22:07
  • Why do you need to merge these interfaces? Why not just ask for both an Interface1 and an Interface2 dependency? What are you trying to achieve by stacking this into a single Interface4 request from the service locator? It's not like you're being charged per request, are you?
    – Flater
    Mar 28, 2023 at 23:40
  • In general, it's preferable to program express dependencies as interfaces which, in a nominal type system, absolutely justifies introducing and interface which extends multiple other interfaces. @Flater if you need a single object that conforms to multiple types then injecting them separately will be useless. Consider I need an object which is equatable and comparable. Jun 17, 2023 at 14:56
  • @AluanHaddad: Semantically, you don't need an object which is equatable and comparable, you need an object which is sortable (which happens to be the same as the sum of equatability and sortability). My argument is one of design mindset. It's not impossible to create an interface that merges other interfaces; but "I need to create a merged interface because I need these two interfaces" is not the right way to go about it. It skips over the very important step of defining the singular behavior of said interface before considering whether it can inherit from other interfaces or not.
    – Flater
    Jun 18, 2023 at 22:50
  • @AluanHaddad: In other words, if you can't describe the new interface's behavior in a meaningful way that is not just deferring to the underlying interfaces it inherits from (because you'd end up with a name like "A and also B"), then you don't need a merged interface. Just because you need two interfaces doesn't mean that you need them on the same dependency (regardless of whether those dependencies might get resolved, outside of your control, to the same concrete object in the end).
    – Flater
    Jun 18, 2023 at 22:52

2 Answers 2

3

The question is, there is needed to create a new interface (let's call it Interface4) that implements Interface1 and Interface2 so I can ask for it like following?

If you want to receive a single object that implements both interfaces, you probably also want to store a single reference to that object. If you declare your reference as Interface1 iA, then you cannot access the Interface2 methods without ugly typecasting tricks and the other way around when you declare it as Interface2 iA.

The only way to declare a reference of a type that can access both Interface1 and Interface2 methods is to create a Interface4 that combines the two interfaces. And your implementation classes would also have to declare they implement Interface4.

And then, if later the component needs an implementation of Interface2 and Interface3 then a creation of Interface5 would be needed? What is the best approach to handle this interfaces?

If you regularly have this problem, you need to critically re-evaluate how you determine which interfaces you need. Maybe you should not have created Interface1, Interface2, and Interface3 at all, but only Interface4 and Interface5.

1

Well, you could do that. Or:

Interface1 i0 = new Implementation1();

Just do that high up the call stack (say in main maybe) and pass it into something that needs it. That thing can use it as an object that implements Interface1 without knowing or caring that it happens to be Implementation1.

Creating Inferface4 is only really justified if something uses the object that way. At best, creating interfaces just to make a service locator happy is a hack. Interfaces and objects (even singleton objects) were never meant to have an exclusively 1 to 1 relationship. Interfaces are meant to express what the client (using) code needs.

It's also worth noting that interfaces aren't the only kind of key your service-locator/container/map can use. So if your code base doesn't naturally have that 1 to 1 relationship you don't have to force it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.