Applied Design Patterns with Java
Structural :: Adapter (137) {C ch 9}
Implementation
Here are implementation issues to consider when using the
Adapter pattern:
- Implementing class adapters in C++. In a C++ implementation of a class adapter, Adapter would inherit publicly from Target and privately from Adaptee. Thus Adapter would
be a subtype of Target but not of Adaptee. All inheritance in Java is public.
- Pluggable
adapters. There are many ways to implement pluggable adapters for
the TreeDisplay widget described earlier, which can lay out and display a hierarchical structure automatically.
First find a "narrow" interface for Adaptee, the smallest subset of operations that lets us do the adaptation.
A narrow interface consisting of only a couple of operations is easier to adapt than an interface with dozens
of operations. For TreeDisplay, the adaptee is any hierarchical structure. A minimalist interface might include
two operations, one that defines how to present a node in the hierarchical structure graphically, and another that
retrieves the node's children.
DirectoryTreeDisplay specializes the narrow interface so that it can
display directory structures made up of FileSystemEntity objects. Here are three approaches:
- Using abstract
operations. Define corresponding abstract operations for the narrow
Adaptee interface in the TreeDisplay class. Subclasses must implement the abstract operations and adapt the hierarchically
structured object. A DirectoryTreeDisplay subclass will implement these operations by accessing the directory structure.
- Using delegate
objects.
TreeDisplay forwards requests for accessing the hierarchical structure to a delegate object. TreeDisplay can use
a different adaptation strategy by substituting a different delegate. TreeDisplay simply forwards the requests
to the delegate, reducing subclassing. Statically typed languages like C++ require an explicit interface definition
for the delegate. We can specify such an interface by putting the narrow interface that TreeDisplay requires into
an abstract TreeAccessorDelegate class. Then we can mix this interface into the delegate of our choice—DirectoryBrowser
in this case—using inheritance. We use single inheritance if the DirectoryBrowser has no existing parent class,
multiple inheritance if it does. Mixing classes together like this is easier than introducing a new TreeDisplay
subclass and implementing its operations individually.
- Parameterized adapters.
A way to support pluggable adapters is to parameterize an adapter with one or more blocks. The block construct
supports adaptation without subclassing. A block can adapt a request, and the adapter can store a block for each
individual request. TreeDisplay stores one block for converting a node into a GraphicNode and another block for
accessing a node's children.
Related Patterns
Bridge
(151) has a structure similar to an object Adapter, but Bridge has a different intent: to separate an interface from its implementation
so that they can be varied easily and independently. An Adapter is meant to change the interface of an existing object.
Decorator (175) enhances another object without changing its interface. A Decorator
is more transparent to the application than an Adapter. As a consequence, Decorator supports recursive composition, which isn't possible with pure
adapters.
Proxy
(207) defines a representative or surrogate for another object and does not change its interface.
Catalog Structural Prev Next