Search code examples
oopinheritanceclass-designprotected

Should protected attributes always be banned?


I seldom use inheritance, but when I do, I never use protected attributes because I think it breaks the encapsulation of the inherited classes.

Do you use protected attributes ? what do you use them for ?


Solution

  • In this interview on Design by Bill Venners, Joshua Bloch, the author of Effective Java says:

    Trusting Subclasses

    Bill Venners: Should I trust subclasses more intimately than non-subclasses? For example, do I make it easier for a subclass implementation to break me than I would for a non-subclass? In particular, how do you feel about protected data?

    Josh Bloch: To write something that is both subclassable and robust against a malicious subclass is actually a pretty tough thing to do, assuming you give the subclass access to your internal data structures. If the subclass does not have access to anything that an ordinary user doesn't, then it's harder for the subclass to do damage. But unless you make all your methods final, the subclass can still break your contracts by just doing the wrong things in response to method invocation. That's precisely why the security critical classes like String are final. Otherwise someone could write a subclass that makes Strings appear mutable, which would be sufficient to break security. So you must trust your subclasses. If you don't trust them, then you can't allow them, because subclasses can so easily cause a class to violate its contracts.

    As far as protected data in general, it's a necessary evil. It should be kept to a minimum. Most protected data and protected methods amount to committing to an implementation detail. A protected field is an implementation detail that you are making visible to subclasses. Even a protected method is a piece of internal structure that you are making visible to subclasses.

    The reason you make it visible is that it's often necessary in order to allow subclasses to do their job, or to do it efficiently. But once you've done it, you're committed to it. It is now something that you are not allowed to change, even if you later find a more efficient implementation that no longer involves the use of a particular field or method.

    So all other things being equal, you shouldn't have any protected members at all. But that said, if you have too few, then your class may not be usable as a super class, or at least not as an efficient super class. Often you find out after the fact. My philosophy is to have as few protected members as possible when you first write the class. Then try to subclass it. You may find out that without a particular protected method, all subclasses will have to do some bad thing.

    As an example, if you look at AbstractList, you'll find that there is a protected method to delete a range of the list in one shot (removeRange). Why is that in there? Because the normal idiom to remove a range, based on the public API, is to call subList to get a sub-List, and then call clear on that sub-List. Without this particular protected method, however, the only thing that clear could do is repeatedly remove individual elements.

    Think about it. If you have an array representation, what will it do? It will repeatedly collapse the array, doing order N work N times. So it will take a quadratic amount of work, instead of the linear amount of work that it should. By providing this protected method, we allow any implementation that can efficiently delete an entire range to do so. And any reasonable List implementation can delete a range more efficiently all at once.

    That we would need this protected method is something you would have to be way smarter than me to know up front. Basically, I implemented the thing. Then, as we started to subclass it, we realized that range delete was quadratic. We couldn't afford that, so I put in the protected method. I think that's the best approach with protected methods. Put in as few as possible, and then add more as needed. Protected methods represent commitments to designs that you may want to change. You can always add protected methods, but you can't take them out.

    Bill Venners: And protected data?

    Josh Bloch: The same thing, but even more. Protected data is even more dangerous in terms of messing up your data invariants. If you give someone else access to some internal data, they have free reign over it.

    Short version: it breaks encapsulation but it's a necessary evil that should be kept to a minimum.