Evaluating Software Design Patterns
— the "Gang of Four" patterns implemented in Java 6

@Pattern(name="Adapter", scope={Class,Object}, purpose=Structural, participants={"Target","Adapter","Adaptee","Client"})

Package dk.rode.thesis.adapter

Implementations and examples of the Adapter design pattern [Gamma95, p.139].


Interface Summary
AdapterDelegate<S,T> An adapter delegate determines how a value of type S can be represented as type T.

Class Summary
AdapterStrategy Simple adapter strategies used in conjunction with SequenceAdapter instances.
IteratorSequence<E> An object adapter that adapts a Sequence type to conform to the Iterator type: when the iterator is advanced, so is the sequence - hence the adaptation.
Main Adapter tests.
SequenceAdapter<E,T> The sequence adapter acts as a generic type adapter for sequence parameterised types, i.e. from Sequence<E> to Sequence<T>, by using an adapter delegate to perform the representation shift.

Enum Summary
AdaptedPolicy Additional policies for formatting SequenceAdapter objects into char sequences (not part of the core Adapter implementation).

Package dk.rode.thesis.adapter Description

Implementations and examples of the Adapter design pattern [Gamma95, p.139].


Here, the Adaptee participant is represented by any Sequence implementation, for example HexDigitSequence.

The IteratorSequence and SequenceAdapter classes represent the Adapter participant.

An IteratorSequence has object scope. The Target of an IteratorSequence is the java.util.Iterator class. An IteratorSequence thus allows iteration over sequence values using standard Java iterators as oppose to using the specific Sequence interface. The IteratorSequence class does not implement the Sequence interface.

A SequenceAdapter essentially has class scope, but is an object adapter, and its Target participant is represented by another Sequence declared with an incompatible type parameter. It utilises AdapterDelegate instances to perform the actual representation shift between types E and T, for example from an Integer value to a String representation of that value.

The Client participant is the test application, i.e. the Main class.

UML Class Diagram:

Implementation notes:
The SequenceAdapter class is an object adapter in that it forwards all sequence requests to the adapted sequence, but a bit unusual in that it does not adapt the raw type, but the instantiated generic type of its own raw type. In that respect it is more related to class adaptation than object adaptation.

Java does not support multiple functional inheritance, so class adapters as described by Gamma et al. cannot be constructed directly. However, using java.lang.reflect.Proxy objects, an object can be adapted to support interfaces dynamically using reflection. As the relationship is dynamic, however, it is related to specific instances, not to a given class directly.

This technique is extensively used in this thesis in the dk.rode.thesis.meta.reflect.proxy package. For example, the ProxyFactory class uses a private internal Proxy target interface that all created proxies will be adapted to, regardless of their type. This enables the proxy factory to access all proxies internally using this common interface, i.e. the factory acts as the client. The adapted proxies and their context are unaware of the adaptation, and all requests to the Proxy interface is never seen by the adaptee: all functionality is "inherited" similar to multiple functional inheritance. The Reference interface is also a target interface adapted by shared objects obtained via a ProxyFactory as well.

A final example is the PrototypeFactory from the Prototype pattern implementation, which adapts objects of any class declaring a copy constructor to the Copyable target interface. The adaptation is public and the context can thus cast the (proxy) object to and from the Copyable type and directly invoke its copy() method.

It is standard in Java to use anonymous inner classes to adapt to a required target interface/class, for example to implement a handler of some sort. The adapter strategies declared in the AdapterStrategy class are all anonymous inner classes that adapts the AdapterDelegate interface. Hence, adaptation is used to construct the required strategies to adapt a given sequence adapter to a target type!

Gunni Rode / rode.dk

Gunni Rode / rode.dk

Feel free to use and/or modify the Java 6 source code developed for this thesis AT YOUR OWN RISK, but note that the source code comes WITHOUT ANY — and I do mean WITHOUT ANY — form of warranty WHAT SO EVER!

The original thesis and source code are available at rode.dk/thesis.