Applied Design Patterns with Java

Structural :: Adapter (137) {C ch 9}

Implementation

Here are implementation issues to consider when using the Adapter pattern:

  1. 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.
  2. 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:

  1. 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.
  2. 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.
  3. 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