Reflection Pattern

The Reflection architectural pattern provides a mechanism for changing structure and behavior of software systems dynamically. It supports the modification of its fundamental aspects such as type structures and function call mechanisms. In this pattern, an application is split into two parts:

  • A meta level provides information about selected system properties and makes the software self-aware. Changes to information kept in the meta level affect subsequent base-level behavior.
  • A base level includes the application logic. Its implementation builds on the meta level.

Also Known as: Open Implementation, Meta-Level Architecture

Example:
Consider a C++ application that needs to write objects to disk and read them in again. Since persistence is not a built-in feature of C++, we must specify how to store and read every type in the application. A solution involves specifying metaobjects that provide run-time type information. For example, to store an object, we must know its internal structure and also the layout of all its data members. With this information available we can recursively iterate over any given object structure to break it down into a sequence of built-in types. The persistence component 'knows' how to store these. If we change the run-time type information we also modify the behavior of the store method.

Meta Level:

The meta level provides a self-representation of the software to give it knowledge of its own structure and behavior, and consists of so-called
metaobjects. Metaobjects encapsulate and represent information about the software. Examples include type structures, algorithms, or even function call mechanisms. Each metaobject encapsulates selected information about a single aspect of the structure, behavior, or state of the base level. However, what you represent with metaobjects depends on what should be adaptable. Only system details that are likely to change or which vary from customer to customer should be encapsulated by metaobjects.

Base Level:

The base level defines the application logic. Its implementation uses the metaobjects to remain independent of those aspects that are likely to change. For example, base-level components may only communicate with each other via a metaobject that implements a specific user-defined function call mechanism. Changing this metaobject changes the way in which base-level components communicate, but without modifying the base-level code. The base level uses the information and services provided by the metaobjects, such as location information about components and function call mechanisms. This allows the base level to remain flexible and its code is independent of aspects that may be subject to change and adaptation. Using the metaobject's services, base-level components do not need to hard-code information about the concrete locations of communication partners, they consult appropriate metaobjects for this information.

MOP:

An interface is specified for manipulating the metaobjects. It is called the metaobject protocol (MOP), and allows clients to specify particular
changes, such as modification of the function call mechanisms. The metaobject protocol itself is responsible for checking the correctness of the change specification, and for performing the change. Every manipulation of metaobjects through the metaobject protocol affects subsequent base-level behavior. Clients of the metaobject protocol, which may be base-level components, other applications, or privileged human users, can specify modifications to metaobjects or their relationships using the base level. The metaobject protocol itself is responsible for performing these changes. This provides a reflective application with explicit control over its own modification. The metaobject protocol is usually designed as a separate component. This supports the implementation of functions that operate on several metaobjects. For example, modifying metaobjects that encapsulate location information about distributed components eventually requires an update of the corresponding function call mechanism metaobjects. If we delegate the responsibility for such changes to the metaobjects themselves, consistency between them is hard to maintain. The metaobject protocol has a better control over every modification that is performed, because it is implemented separately from the metaobjects. To perform changes, the metaobject protocol needs access to the internals of metaobjects. If it is further entitled to change connections between base-level objects and metaobjects, it also needs access to base-level components. One way of providing this access is to allow the metaobject protocol to directly operate on their internal states. Another safer but more inefficient way of providing it is for metaobjects and base-level components to provide a special interface for their manipulation, only accessible by the metaobject protocol.

Reflection and Layers

The general structure of a reflective architecture is very much like a Layered system. The meta level and base level are two layers,
each of which provides its own interface. The base-level layer specifies the user interface for exploiting application functionality. The metalevel
layer defines the metaobject protocol to modify the metaobjects. However, in contrast to a layered architecture, there are mutual dependencies between both layers. The base level builds on the meta level, and vice-versa.

reflection.JPG
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License