Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

com.arcle.rmt.j2se.util.GenericClassMap Class Reference

Maintains a set of mappings between a Class (or interface) and an object. More...

List of all members.

Public Member Functions

boolean visitClasses (ClassMapVisitor v)
 Traverse through all (Class, Object) mappings.

Object findFirstInstance (final Object key)
 Finds the first object which its key is assignment-compatible (an instance of) with the specified key object.

Object getMappedObject (Class key)
 Finds the object which its key is assignment-compatible (an instance of) with the specified class.


Protected Member Functions

abstract Map createMappings ()
 Abstract factory method that shall create and initialize the class-object mappings.

Map getMappings ()
 Accessor method that returns the mappings.


Private Attributes

Map _mappings
 Contains the (Class, Object) mappings.


Detailed Description

Maintains a set of mappings between a Class (or interface) and an object.

Intent
Sometimes a need arise to determine whether an object implements one of a set of known interfaces. This works in analogy to a switch construct that compares an integer variable with a set of known integers to execute the appropriate code block based on the integer.
When the set of integers being compared to is large, we can transform the switch ... case construct using a Map (or hashtable) object, using the integer variable as a key to access the appropriate code block stored as values in the Map.
Back to the integer comparison case. Since comparing an object with set of interfaces cannot be done in a switch statement, we often end up with the if .. else equivalent of a switch statement:
if (object instanceof AnInterface) { something.doSomeThing(object); } else if(object instancof AnotherInterface) { somethingElse.doSomeThing(object); } else if(object instanceof YetAnotherInterface) { anotherThing.doSomeThing(object); } ...
Motivation
When the set of interfaces is large, the size of this construct increases linearly with the number of interfaces. Since long lines of if .. else statements degrade modularity (and simply not pretty), we need a better solution to handle problems like these.
Solution
Since a long block of switch statement can be replaced by indexing a Map object, we do the approximately analogical thing with a Class as the key. An object is used to "index" a Map to see which interface is implemented by this object, and obtain the value associated with the interface implemented by the original object.
With GenericClassMap, the former long string of if statements can be shortened into a relatively small code block. This code fragment looks like this:
// the following instantiation is only needed to be executed once. GenericClassMap thingMap = new ThingMap();

// do the "indexing" Thing something = (Thing) thingMap.findFirstInstance(object); if (something != null) { something.doSomeThing(object); }

For the above code to work, we need to define the mappings between the interfaces and the objects that need to work on objects that implements the former interface. Although code to instantiate this mapping may be almost as long as the original if..else if constructs, we will save coding efforts when there are more than one block of if ... else if statements required on the same set of (interface, object) pair.
Another advantage of this approach is that the instantiation of class-object mappings can be done its own class, separate from the code that performs the search. By encapsulating the mappings, it further increases modularity and maintainability of program code.
Strategy
The mappings between (interface, object) are made by inheriting a class from GenericClassMap and overriding the createMappings() factory method to establish the required mappings. An example follows:
public class ThingMap extends GenericClassMap { protected Map createMappings() { Map mappings = new Hashtable(); mappings.put(AnInterface.class, new SomeThing()); mappings.put(AnotherInterface.class, new SomeThingElse()); mappings.put(YetAnotherInterface.class, new AnotherThing()); return mappings; } }

Having established the (Class, Object) mappings, the long string of if .. else statements can be replaced by a single call to findFirstInstance() which will return the desired object based on an implemented interface.
Note:
Unlike indexing a hashtable which takes constant time, checking whether an object implements a certain interface requires the object to be compared against all intefaces in the set. Therefore the "index" operation offered by findFirstInstance() takes linear time proportional to the amount of interfaces registered.

The code saving gained by GenericClassMap is obtained at a cost of a minor inflexibility: we no longer have control of the ordering of the classes/interfaces being compared. If an object x that implements two interfaces A and B is used to index the class map, there is no guarantee which interface will be selected; the mapped object of any one of those interfaces may be returned by findFirstInstance().

Author:
Sasmito Adibowo
Version:
Id
GenericClassMap.java,v 1.9 2003/05/15 19:43:56 adib Exp

Definition at line 181 of file GenericClassMap.java.


Member Function Documentation

abstract Map com.arcle.rmt.j2se.util.GenericClassMap.createMappings  )  [protected, pure virtual]
 

Abstract factory method that shall create and initialize the class-object mappings.

Referenced by com.arcle.rmt.j2se.util.GenericClassMap.getMappings().

Object com.arcle.rmt.j2se.util.GenericClassMap.findFirstInstance final Object  key  ) 
 

Finds the first object which its key is assignment-compatible (an instance of) with the specified key object.

Parameters:
key Search for a class that is assignment compatible with this key.
Returns:
The mapped object if found, null otherwise.

Definition at line 208 of file GenericClassMap.java.

References com.arcle.rmt.xplat.util.MutableReference.value, and com.arcle.rmt.j2se.util.GenericClassMap.visitClasses().

Object com.arcle.rmt.j2se.util.GenericClassMap.getMappedObject Class  key  ) 
 

Finds the object which its key is assignment-compatible (an instance of) with the specified class.

Parameters:
key search for a key that is assignment compatible with this key.
Returns:
the mapped object if found, null otherwise.

Definition at line 229 of file GenericClassMap.java.

References com.arcle.rmt.j2se.util.GenericClassMap.getMappings().

Map com.arcle.rmt.j2se.util.GenericClassMap.getMappings  )  [protected]
 

Accessor method that returns the mappings.

Definition at line 242 of file GenericClassMap.java.

References com.arcle.rmt.j2se.util.GenericClassMap._mappings, and com.arcle.rmt.j2se.util.GenericClassMap.createMappings().

Referenced by com.arcle.rmt.j2se.util.GenericClassMap.getMappedObject(), and com.arcle.rmt.j2se.util.GenericClassMap.visitClasses().

boolean com.arcle.rmt.j2se.util.GenericClassMap.visitClasses ClassMapVisitor  v  ) 
 

Traverse through all (Class, Object) mappings.

Returns:
when true, all mappings was visited.

Definition at line 187 of file GenericClassMap.java.

References com.arcle.rmt.j2se.util.GenericClassMap.getMappings(), and com.arcle.rmt.j2se.util.ClassMapVisitor.visitClassMap().

Referenced by com.arcle.rmt.j2se.util.GenericClassMap.findFirstInstance().


Member Data Documentation

Map com.arcle.rmt.j2se.util.GenericClassMap._mappings [private]
 

Contains the (Class, Object) mappings.

Definition at line 252 of file GenericClassMap.java.

Referenced by com.arcle.rmt.j2se.util.GenericClassMap.getMappings().


The documentation for this class was generated from the following file:
Generated on Fri Jun 18 19:55:00 2004 for Arcle Rambutan by doxygen 1.3.5