Why use this strange convention - wouldn’t a Map be good enough?
Other platforms do use string-keyed maps for this sort of thing, but there are some weaknesses with that approach:
-
it is impossible to enforce dependencies. With
Lookup
, a module’s code cannot request an object of type X unless it can load/access theX.class
. The module trying to look up an X will not be able to seeX.class
unless it declares a dependency on the module that defines X and the module which defines X says that it allows access to the Java package X lives in. (AMap<Class<T>,T>
would do the same job asLookup
.) -
The class of values in a map can change without notice - so if you have
(SomeIface) foo = (SomeIface) globalMap.get("foo")
, some new version of the module that provides "foo" can change the return type, causingClassCastException
s; withLookup
, you cannot ever get an object that is not of the type you passed in the request - so Lookup’s approach is more robust. -
Lookup
supports listening to changes in the result. -
Lookup
supports multiple instances for one key - if you calllookup(X.class)
you get one instance. If you calllookupAll(X.class)
you get aCollection<? extends X>
(so withlookupAll()
it is more like aMap<Class<T>,List<T>>
)
There are some other capabilities of Lookup
(such as getting the specific type or number of results without actually creating objects, and providing named result items) but these are rarely used in practice.
Lookup
is very powerful, yet simple and generic; people quickly learn to love it, once they realize what it can do.
See also the javadoc: Lookup