Java – Interface Design with Interdependent Yet Decoupled Packages

designinterfacesjavalibrariespackages

I plan to write a library in Java, consisting of packages A, B, C and so on. Every package encapsulates a part of the big picture. B relies on A, C on B and so on. For this purpose every package offers a single class to the next package. However, every package is optional in that the user can decide to substitute their own implementation. How do I construct the interfaces (concept, not Java entity) between the packages?

My first idea was to simply putting an interface (Java entity) and an implementing class into the package with lower ordinal number, i.e. interface AtoB and class AtoBImpl into A etc. However, if a user of the library does want to use package B but provide their own implementation for A, they not only have to import B.*, but also A.AtoB. While this may not be a big deal, it looks like a better solution might exist.

My second idea was to create extra packages only for the interfaces, i.e. a package AtoB containing an interface AtoB. The implementation of that would still reside in A. A user using B but not A now has to import B.* and AtoB.*, but no references to A remain. This looks cleaner to me but also more unwieldy.

My third idea was to put all interfaces into a common package, i.e. a package inter containing interfaces AtoB, BtoC etc.

Is there a best practise? Or another, better approach? Am I splitting hairs? Thanks!

Best Answer

The Java interface looks like the most common and best solution for this issue. However, i strongly recommend putting interface close to the code that depends on them. Its no concern of package A that B depends on it; however, it is very much a concern of package B that it depends on A.

I'd therefore go with a structure like this:

package A
    class AtoBImpl implements B.FromA

package B
    public interface FromA

Users of B but not of A now have to import solely from B.

If you dont like to reference B from A, you could also go with this:

package A
    class AtoBImpl

package B
    public interface AtoB
    public class AtoBImplAdapter implements AtoB
        @Inject private A.AtoBImpl