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

@Pattern(name="Proxy", scope=Object, purpose=Structural, participants={"Proxy","Subject","RealSubject"})

Package dk.rode.thesis.proxy

Implementations and examples of the Proxy design pattern [Gamma95, p.207].

See:
          Description

Class Summary
ImmutableSequence<E> An immutable sequence ensures that invocations of NonResettableSequence.reset(), ImmutableSequence.next(), and ImmutableSequence.copy() are ignored for the proxied sequence if and only if the proxied sequence is accessed through the proxy only.
Main Proxy tests.
NonResettableSequence<E> A non-resettable sequence ensures that invocations of NonResettableSequence.reset() are ignored for the proxied sequence if and only if the proxied sequence is accessed through the proxy only.
SequenceProxyFactory A sequence proxy factory creates various dynamic proxies for any type of sequence.
SynchronisedSequence<E> A synchronised sequence ensures thread-safe access to a proxied sequence if and only if the proxied sequence is accessed through the proxy only.
 

Enum Summary
ProxiedPolicy Additional policies for formatting proxied sequences into char sequences (not part of the core Proxy implementation).
 

Package dk.rode.thesis.proxy Description

Implementations and examples of the Proxy design pattern [Gamma95, p.207].

Intent:

Here, the Subject participant is represented by the Sequence interface, and the RealSubject participant by any Sequence implementation, for example PrimeSequence, EnglishAlphabetSequence, LongSequence, etc.

The Proxy participant is represented by the specific proxy sequence classes defined in this package that control the access to the real subjects, i.e. sequences, namely SynchronisedSequence, and NonResettableSequence, and ImmutableSequence. They all work via the Decorator pattern, decorating the actual Sequence in order to control access to it.

However, the Proxy participant is also represented by any sequence proxy returned by the SequenceProxyFactory class. It utilises Java's java.lang.reflect.Proxy class that allows for runtime adaptation of interface behaviour using reflection. The factory defines three specific factory methods to create proxies based on any Sequence, mimicking the SynchronisedSequence, NonResettableSequence, and ImmutableSequence classes, respectively SequenceProxyFactory.getSynchronisedSequence(dk.rode.thesis.meta.model.Sequence), SequenceProxyFactory.getNonResettableSequence(dk.rode.thesis.meta.model.Sequence), and SequenceProxyFactory.getImmutableSequence(dk.rode.thesis.meta.model.Sequence).

It also supplies a factory method to create a proxy that will log all access to the proxied object in form of the SequenceProxyFactory.getLoggableSequence(dk.rode.thesis.meta.model.Sequence) factory method, as well as the SequenceProxyFactory.getVirtualSequence(dk.rode.thesis.meta.reflect.InstantiableTypeLiteral, Object...) factory method that will create a sequence proxy that will delay creation of the actual Sequence instance until the first Sequence method is invoked. Finally, the SequenceProxyFactory.getSharedSequence(dk.rode.thesis.meta.model.Sequence) method allows a given sequence to be shared among copies of it until a copy invokes either next() or reset(), which will detach the copy from the shared reference.

UML Class Diagram:

Implementation notes:
The java.lang.reflect.Proxy class is quite flexible. It allows casting to any (runtime) implemented interface, so type information need not be lost for the proxied sequences. A proxy that works as a (dynamic) Decorator will effectively change the type (class), so casts and instanceof tests will fail for interfaces implemented by the proxied object. This is the case with the fixed proxy classes created in this package. For example, a ReversibleSequence proxied by the SynchronisedSequence class will to the context no longer be reversible, because SynchronisedSequence do not implement the ReversibleSequence interface. A java.lang.reflect.Proxy instance representing a Sequence that implements ReversibleSequence still allows casts and instanceof tests.

The price of using java.lang.reflect.Proxy instances is naturally speed as the implemented interfaces are accessed using reflection in form of a java.lang.reflect.InvocationHandler instance. However, reflection in modern JVM's is quite fast, so it is probably acceptable in most cases. Also, though a java.lang.reflect.Proxy object can be cast into any runtime implemented interface, the original type (class) information of the proxied object is lost. Class cast exceptions can also occur. Once a proxy instance is created based on a specific set of interfaces, the instance represents a unique proxy class that implements these exact interfaces. Creating another proxy instance with the same ordered set of interfaces will reuse the proxy class. The returned proxy is thus an instance of that proxy class and not the original type, for example a LongSequence. There are also other problems with such proxies, for example marshaling and serialization.

For an in-depth introduction to the java.lang.reflect.Proxy class, please refer the its JavaDoc documentation.

Gamma et al. define four overall types of proxies: remote proxy, virtual proxy, protection proxy, and smart reference [Gamma95, p.208-209]. The getVirtualSequence method returns a virtual proxy. The NonResettableSequence and ImmutableSequence classes represent protection proxies and so do the proxies returned by the getNonResettableSequence and getImmutableSequence methods. The SynchornisedSequence class as well as the proxy returned by the getSynchronisedSequence method represent a smart reference. The getSharedSequence method also returns a smart reference, more precisely a smart pointer. This package defines no remote proxies, but an example could be a sequence fetching its values using a socket channel to a sequence on a different machine or JVM delivering the values.

Author:
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.