4

I am writing my first "API jar" that will be open source library and used by (possibly) other developers. I've read Joshua Block's thesis on effective API design, and one of the things he talks about - that I never would have thought of otherwise - is his concepts of minimizing access and maximizing information hiding. Basically, you only want your API developers to have access to the Java objects they will be using, and you don't want your API developers to have access to any of the "guts" of your library.

In my several years as a Java developer, I've never had the need to make a class anything other than public. Furthermore, I've never used nested classes either. So I'm sitting here wondering how do I implement this "information hiding" best practice in my Java API? And I think private, and possibly nested, classes is the answer. But where to begin?

  • Every .java source file requires at least 1 public class in it to compile. So for me to make a class private (and non-nested), I need to "bundle it with a public class. To me this makes sense only if the public/private classes are heavily related. But what if I have a section of my API that just consists of private classes (for accessibility-minimizing-purposes) that don't relate to any other public analogs?
  • When do you make a private class nested, and when do you make it non-nested? Or is it just a matter of preference?
IAmYourFaja
  • 50,141
  • 159
  • 435
  • 728
  • 1
    You can publish the API in an interface and make all implementations package local, for instance. Also, this is not true that a Java source file requires a public class: your class can be package local. You can declare `class XX {}` in XX.java. This means XX will only be accessible from the same pacakge. – fge Dec 22 '12 at 13:11
  • 1
    With regard to nested classes you should consider also when to use non-static nested classes (inner classes) and when to use static nested classes. You may like reading this SOF question: http://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class – Diego Pino Dec 22 '12 at 15:34

3 Answers3

4

Classes that are package-private (i.e. don't have any visibility modifier) are only visible by the classes of the same package. That's a way to make a class visible by several other classes of your API, but not by the outside world.

Nested private classes are also useful to make a non-public class, and their scope is even narrower: they're only visible by the enclosing class.

I suggest having a look at Guava's source code for an excellent API design. You'll see all kinds of techniques to hide internals to the outside there.

Louis Wasserman
  • 172,699
  • 23
  • 307
  • 375
JB Nizet
  • 633,450
  • 80
  • 1,108
  • 1,174
3

Personally, I don't believe in private. I use protected instead whenever feasible to allow for some of the major benefits of OO design.

Basically the 'information hiding' principle is not bad as a guideline. However, in practice one should not blindly follow it in all cases. - For the pure principle you would, as others suggested, need to define a set of interfaces as public and hide all the rest of your lib away with package-private classes, factory methods, and the like. Given that Java's package-private visibility has some issues that render it somewhat useless in many cases (- classes within your lib will want to cooperate across packages -) this in turn seems to prevent such an approach.

Besides, there are always at least two types of users of an API: the basic users, who will use the objects and methods you provide, and the users with complex requirements, who will want to modify the API's behavior (at least) by inheritance, which a lot of 'hidden' stuff will successfully prevent.

Don't be shy to make those things public for which it may make sense, make things protected which are not really needed to be public, and make only those things private which may cause harm if directly accessed by anything but their directly related code.

Another note: The hiding-principle has as a major purpose to simplify the use of your code by others and to imply and encourage the correct use thereof. But remember that documentation is another important means to achieve this; and documentation will be needed for a library anyway. - If you have 100 public methods and your docs state which 10 of those are needed for a use case the user of your lib will probably get along with that just as well as he would if only those 10 were visible to him.

JimmyB
  • 11,178
  • 1
  • 23
  • 42
  • As a programmer who relies excessively upon autocomplete, I don't agree with your last point - documentation won't achieve this. The best way to achieve conceptual simplicity is to limit choices. – Fabian Tamp Sep 24 '15 at 08:19
  • 1
    Good answer. Hiding information is good in general, but can be a major pain inside a library that will surely have unforeseen use-cases. – kaqqao Mar 18 '16 at 12:45
  • Your mention of *"the users with complex requirements, who will want to modify the API's behavior (at least) by inheritance, which a lot of 'hidden' stuff will successfully prevent"* is ringing very true right now for me - All I wanted to do was to extend a class in Google's HTTP client library, but due to things being `private` I'm having to import the entire library source code as a local module that I can modify..... – You'reAGitForNotUsingGit Jul 20 '18 at 02:25
1

I do believe in private. I've been working on framework classes quite some time and Joshua is right in telling you that you should hide as much as possible. The reason behind it is that everything that you expose will be used. And once it is used, you can't change it without breaking client code. Everything, that is not private, is accessible from clients! Basically you should work with package private classes, only allow inheritance where useful and make only those classes public that are absolutely necessary to make your lib useful. When extending functionality, the "interface segregation principle" is your friend.

Fabian Tamp
  • 4,026
  • 1
  • 22
  • 41
sorencito
  • 2,429
  • 17
  • 21
  • ... and I have been using frameworks for long enough to have seen seriously flawed use of visibilities in almost every one of them. I think it is not a bad thing if "everything that you expose will be used". Of course, if you declare everything private you have the freedom to change everything at your discretion any time. But to me that is a bit of too black&white. Let users use the code you have written! - Otherwise they will either keep re-inventing wheels or will derive their own version of your sources which eliminates the possibility to update later. – JimmyB Dec 22 '12 at 18:21
  • Indeed, there is nothing bad when everything that is exposed is used! I just say: only expose what you want to be used. Otherwise users will see that their code stops working because some public "internals" in the lib changed. – sorencito Dec 22 '12 at 18:40
  • Also see the open closed principle: a lib should be closed for modification, but open for extensions. http://www.oodesign.com/open-close-principle.html – sorencito Dec 22 '12 at 18:42
  • I second that; especially the 'extensibility' part, of course :) - However, it seems to me that many programmers fail to (fore-)see why and how users will want to extend their code - and a single method or field carelessly declared `private` (or even lazily 'declared' package-private) can exclude a whole lot of useful extensibility. Thus, I endorse *careful* and reflected use of visibilites; and in that, I think, we agree after all. – JimmyB Dec 22 '12 at 18:57
  • Yes. Always consider visibilities well :-) – sorencito Dec 22 '12 at 19:06
  • 1
    If a class is not carefully designed to be extendable, and is not intended to be extended, it should be final. That's another recommendation of Josh Bloch, IIRC. But extending a framework or API can be done (and, most of the time, should be done) without extending any class, but by wrapping them and using delegation instead of inheritance. – JB Nizet Dec 22 '12 at 20:58
  • I couldn't agree more. If the framework uses interfaces, it is very easy to make it use your own implementations, which in turn rely on delegating to Framework code without reinventing the wheel. – sorencito Dec 23 '12 at 07:15
  • I'm curious: Do you have any actual frameworks in mind in which this structure can be seen 'in action' as an example? – JimmyB Dec 23 '12 at 23:48
  • Hehe...I can at least show you the counterexample: look at Dozer and try to update it to the next version after using it for a while ... – sorencito Dec 24 '12 at 08:54