- Metaphors
- Issues
- Interfaces
- Implementations
- Collections
- Extending Collections
- Conclusion
Extending Collections
I have often seen classes that extend one of the collection classes. A Library holding a list of books, for example, could be implemented by extending ArrayList:
class Library extends ArrayList {...}
This declaration provides implementations of add() and remove(), iteration, and the other collection operations.
There are several problems with extending collection classes to get collection-ish behavior. First, many of the operations offered by collections will be inappropriate for clients. For example, clients generally shouldn’t be able to clear() a Library or convert it toArray(). At the very least, the metaphors are mixed and confusing. At worst, all these operations need to be disinherited by implementing them and throwing an UnsupportedOperationException. It’s not a good trade-off to inherit a few useful lines of code but spend far more lines eliminating functionality you don’t want. The second problem with inheriting from collection classes is that it wastes inheritance, a precious resource. To pick up a few lines of useful implementation, you preclude using inheritance in some more highly leveraged way.
In such a situation, it is better to delegate to a collection rather than inherit from one:
class Library { Collection<Book> books= new ArrayList<Book>(); ... }
With this design, you can reveal only those operations that make sense and you can give them meaningful names. You are free to use inheritance to share implementation with other model classes. If a Library offers access to books by several different keys, you can name the operations appropriately:
Book getBookByISBN(ISBN); Book getBookByID(UniqueID);
Only extend collections if you are implementing a general-purpose collection class, something that could be added to java.util. In all other cases, store elements in a subsidiary collection.