Fall Back On Reflection

Problem:

How can you BuildInterfaceImplementationPairs when the implementation will be different for each class that implements the interface?

Context:

You have defined an abstract component interface that allows components' services to be queried and connected to other components. The implementation of the component interface will be different for each concrete component type but you don't want component developers to be overly burdened by the component model; they should concentrate on implementing the functional aspects of their component rather than its "packaging".

Therefore:

  1. Define coding conventions for the definition and implementation of component services.
  2. Provide an implementation of the component interface that uses reflection to determine the services of derived classes by their use of the coding conventions.

Resultant Context:

  1. Developers get the appropriate implementation of the interface "for free" by merely following the coding conventions.
  2. Developers must follow the coding conventions in order to make use of the default implementation of the interface.
  3. The implementation of the interface that uses reflection is usually less efficient than an implementation coded by hand.

However, developers can implement the interface by hand if they cannot follow the coding conventions for some reason or if they find the performance of the default implementation to be too poor.

Comments:

This is especially useful in frameworks in which components are dynamically instantiated and plugged together, such as JavaBeans, PipesAndFilters or in my case, a Java framework for dynamically building transport protocols from lightweight components.

Known Uses:

JavaBeans uses reflection to determine those properties of a bean that are not described by its associated info class.

The Regent transport framework [http://www-dse.doc.ic.ac.uk/~np2/regent] uses reflection to determine the services and control interfaces of protocol layers that have not overridden the default query methods.

JavaUnit (a unit testing framework) by ErichGamma and KentBeck uses it. The default implementation of a test case uses reflection to find all test methods in the test subclass.

http://www.javaworld.com/javaworld/javatips/jw-javatip57.html shows how to use coding conventions and reflection in a similar way to define and query applet parameters without having to write lots of boilerplate code for each new applet class. Source code is included.


For example:

JavaBeans components are classes that come with associated "packaging"; the packaging provides development tools with the information they need to support graphical composition of the beans. JavaBeans packaging is defined as a set of interfaces that expose the properties, events and methods of the bean. Implementing these interfaces by hand is a tedious task that involves writing boilerplate code many times, only changing a few names each time.

Therefore, rather than forcing programmers to implement the packaging interfaces themselves, the Bean implementors FallBackOnReflection: they provided an implementation of the packaging interfaces that uses reflection to determine the properties and events of a bean based on simple coding conventions. Thus programmers can concentrate on the functional aspects of their beans rather than wasting time writing the packaging.

One might ask, why not ditch the interfaces and rely only on reflection? In Java, invoking a method by reflection is about 100 times slower than using a polymorphic call, so you want to allow programmers to replace reflection if performance becomes a problem. Therefore you provide abstract interfaces that can be implemented by hand for speed and a default implementation that uses reflection.

-- NatPryce

There's another example in JavaUnit, where the test methods follow a certain naming convention which the core engine uses to discover and invoke them via reflection. Specifically, the code in TestSuite searches for method names beginning with "test". VectorTest? implements testCapacity(), testContains() and so forth, and TestSuite finds and calls them. Those methods are not part of some common interface.

Without reflection, we would either have to give the methods standard names like test1(), test2() etc, or else put each test into its own class with a single method called test().

-- DaveHarris

Even better is if you can easily attach CustomMetaData to a method. So, instead of encoding semantic information into a method name you can explicitly mark methods as test methods. The ScarletLanguage uses this so you can simply write something like 'def test-contains() [test]'. C# also supports this sort of usage. -- JesseJones

Java 5 now supports annotations.


See ReflectionVsCodeGenerationArticle


CategoryPattern CategoryReflection

EditText of this page (last edited June 17, 2010) or FindPage with title or text search