Sponsored Link •
Bill Venners: Another design principle you listed was, "Hide as much of the implementation as possible." What is that about?
Elliotte Rusty Harold: That's just a good general principle of object-oriented programming. You want to expose a certain API and keep everything else private. You don't want your clients to see how you are doing certain things that they don't need to know.
If you expose too much, there are two costs. One is, it confuses the client programmers. It takes mental effort to learn and understand these things, and hey, they don't need to know. Smaller is better. Smaller is simpler. That's one of the big advantages of data encapsulation that's not often pushed in object-oriented textbooks, though I think it's one of the most important in practice.
The other advantage to implementation hiding is very well known: it allows you
to vary the implementation. If later you decide that
java.lang.String class isn't fast enough for your needs, you can
change the implementation to use arrays of
chars. You can get
away with that kind of change without breaking client code.
Hiding implementation also means that clients can't sneak behind the public methods and break things by calling methods out of order than the implementation would normally call them, for example. But far and away the most important practical reason for encapsulation is it makes the classes simpler and easier to understand.
Bill Venners: You also mentioned in your talk, "Design for subclassing or prohibit it."
Elliotte Rusty Harold: That is taken directly from Joshua Bloch's book Effective Java. If you're going to allow subclasses, you must remember that subclasses typically need to have a greater access to the superclass members than the general public. Subclasses also need to access the superclass in different ways from the general public. So designing for subclassing takes extra effort. You really need to think about what a subclass is going to do, what it can do, what it should be able to do. It is much harder to get the design right for a subclass than just for a client object that's merely invoking the methods.
That being said, sometimes subclasses are in fact useful, so you do the work. If you don't do the work, if you don't really think about what subclasses do and don't need and how they'll interact with the superclass, you should make the class final to prevent it from being subclassed. Because often, subclasses sneak behind the normal barriers of access protection, and they can get at pieces of the class in ways you had not intended.
So one principle I follow in design is that all classes start their life as final. If at some point I discover a reasonable need to subclass, either my own or somebody else's, then I will remove the final modifier. I take this approach because once a class is published as non-final, it becomes very hard to make the class final later on.