I'm making a library or two for and Android app and I want to keep the library's exposed interfaces to a minimum to avoid the abstraction leaking everywhere by avoiding making all of the classes 'public'. I'm also following Maven's package structure.
Coming from C#, I've used the internal
access modifier to accomplish what I want; if you're not familiar, internal
grants access to anything within the assembly, but not outside of it. So the few public interfaces are truly public. The closest analogy, in my opinion, is package-private
in Java, but that doesn't quite work when I organize my library into subpackages.
For example, say I have a class Service1
in root and another class Service2
in a subpackage under root. I'd like Service1
to be able to reference Service2
's interface, but preferably not make Service2
public
as that'd expose Service2
's interface outside of the package, which isn't what I intend.
I imagine this isn't terribly complicated, but I'm a little bit confused as to how to allow sibling/parent packages to access subpackage classes without making them public
. The only solution I've been able to really think of is to either 1) put everything at the same package level which would allow me to use package-private
to hide everything that shouldn't be publicly available but is extremely messy or 2) suck it up and make my interfaces public, which admittedly offends my sensibilities.
How is this normally done? Are all the classes in the same package, but possibly organized by subdirectories? I've yet to come up with an approach that I truly like.
Best Answer
In Java, your intended API surface should define your package structure. Avoid the temptation to create subpackages just to "organize" your files in a way that doesn't directly relate to your API design. The perceived need to do so may even hint at poor API design.
With that in mind, you may still want to use a subpackage to create an internal API. For example, a group of classes might want certain members to be accessible to other classes in the group, but not expose those members to the rest of your library. In that case, put them in a subpackage and take advantage of package-private access. You'll need to think carefully about whether the exposed API of the subpackage is something you want to design, document, and support as a separate product. Doing so will make your product more valuable, but of course at some cost to you. If you don't want to support the internal API, or you're not sure yet, the usual solution is to put that API in a subpackage with a name that identifies it as internal, like
com.myproduct.internal
, or even an entirely different package hierarchy, like thecom.sun
classes that are exposed by necessity but officially not part of the standard Java API.