EXTENDING COLLECTION CLASSES The standard Java Collection classes are a very nice API, but they are limited and should be extended. Many extensions make the common mistake of enforcing the type too much. For example, we'll extend HashMap to form three new Map classes: OrderedHashMap, UniqueHashMap, and DebugHashMap. OrderedHashMap maintains the order in which elements were added to the HashMap, UniqueHashMap doesn't allow a key-value pair in if the value is already in the HashMap, and DebugHashMap prints out information about what's happening to the map. Ordered and Unique both have empty constructors, while Debug takes a Writer. Each class extends HashMap to save on coding time. HashMap ordered = new OrderedHashMap(); HashMap unique = new UniqueHashMap(); HashMap debug = new DebugHashMap(new PrintWriter(System.err)); Sometimes a Map can be passed to the constructor to initialize values. Here is an example of the constructor code: public OrderedHashMap(Map map) { this(); putAll(map); } The Map is copied across so as to not violate encapsulation by allowing a user to perform actions upon the Map later and because it fits the HashMap extension better. However, problems arise when we try to use these HashMaps together. How do we create an OrderedTreeMap, a UniqueTreeMap, or an Ordered HashMap that only allows Unique values? The Collections designer has to learn to trust the user, allow the user to violate the principle of encapsulation, and avoid the extension of a particular implementation of Map. This is simple to do. Rather than extending HashMap, just implement Map and have the following constructors: private Map proxiedMap; /** * HashMap is the default type of internal map. */ public OrderedMap() { this(new HashMap()); } public OrderedMap(Map map) { this.proxiedMap = map; // do any initialisation work on map's values } The rest of the class then acts upon the proxiedMap attribute rather than relying on the inheritence. This is improved somewhat by creating a ProxyMap class, which delegates all method calls to an internal, delegated Map. For example: public Object put(Object key, Object value) { return this.proxiedMap.put(key, value); } OrderedMap can extend ProxyMap and get the same benefit that's obtained by extending HashMap. The biggest advantage with this change of style is that the following becomes possible: Map map = new OrderedMap( new UniqueMap( new DebugMap( new HashMap() ) ) ); This saves a lot of wasted developer hours. To change the previous code to a TreeMap, use the following example: Map map = new OrderedMap( new UniqueMap( new DebugMap( new TreeMap() ) ) ); The same principle applies to any Collection, not just Maps. It allows you to create powerful data structures in Java that save time, money, and wasted code. ----------------------------------------