First, note that Item 29 is really about the general concept of using parameterized keys:
Sometimes, however, you need more flexibility. For example, a database row can have arbitrarily many columns, and it would be nice to be able to access all of them in a typesafe manner. Luckily there is an easy way to achieve this effect. The idea is to parameterize the key instead of the container.
The intent of this item is to demonstrate that you can use generics in more ways than just by parameterizing a type. The Heterogeneous Container pattern is simply an example of this technique. Admittedly, the item could make that point clearer with a better title like "Consider using parameterized methods to enforce type safety when working with arbitrary numbers of types".
The Heterogeneous Container pattern the item demonstrates is specifically for the case where you want to associate certain types with a particular instance of each type. Guava includes an implementation of this pattern with their ClassToInstanceMap
type (more details). They also provide the more powerful TypeToInstanceMap
that supports arbitrary generic types (e.g. List<String>
) with an admittedly slightly more cumbersome API.
All of this is to say that there's nothing stopping you from creating a similarly structured class that supports multiple instances of a given type. We could easily take the ClassToInstanceMap
API and create a ClassToInstanceMultimap
type (extending Guava's Multimap
API):
public interface ClassToInstanceMultimap<B> extends Multimap<Class<? extends B>, B> {
/**
* Returns the values the specified class is mapped to, or an empty collection if no
* entries for this class is present. This will only return a value that was
* bound to this specific class, not a value that may have been bound to a
* subtype.
*/
<T extends B> Collection<T> getInstances(Class<T> type);
/**
* Stores an entry mapping the specified class to the specified value. Does <i>not</i>
* associate this value with any of the class's supertypes.
*
* @return {@code true} if the method increased the size of the multimap, or
* {@code false} if the multimap already contained the key-value pair and doesn't allow
* duplicates
*/
<T extends B> T putInstance(Class<T> type, T value);
}
Guava doesn't currently include such an interface, but the implementation of ClassToInstanceMap
is pretty straightforward, so you could easily create your own ClassToInstanceMultimap
implementations.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…