Adapter pattern

author-image
CIOL Bureau
Updated On
New Update

Avijeet Dash & Satyabrata Dash

Advertisment

Intent

Convert the interface of a class into another interface that clients expect.

In 30 Seconds

Here the catch is "achieving reusability by converting an existing interface to a new interface". Let’s say we have a class ‘’A’’ that has getX() method signatures. But the client code uses get ("X") method signature for calculation. Now how to bridge this interface (function signature) difference?

Advertisment

We need can use an one Adapter class here to wrap the which will convert all
the getX() methods to inside get("X") methods. We can write an adapter
(wrapper) class ‘B’ around ‘A’ to make it act like a hash table (this is
the target interface which will give us get ("X") type of signature).
Adapter (B) adapts the Adaptee (A) interface to the Target’s ( HashTable)
interface. Thus avoids rewriting all the Adaptee (A) code just for the sake of
the new interface.

Motivation

Two styles of implementation of the pattern are possible. We can implement
the pattern in two ways: class adapters and object adapters. Class
adapters are realized by subclassing both target interface and the adaptee
implementation. This is to yield a single object (multiple inheritance). Object
adapters are realized by delegating operations from the adapter object to the
adaptee object by having adaptee object as attributes (object composition).

Advertisment

A class adapter uses inheritance so it can be used to adapt only a class and
all its parents but not subclasses. A Class adapter introduces only one object
and hence, avoids additional pointer indirection (which happens in languages
like c++ where pointers are used for object references). Object adapters on the
other hand use composition to make an Adapter work with many Adaptees. Here
Adapter can’t override Adaptee behavior as it is doesn’t know which Adaptee
it is working with.

Structure

Advertisment

Class Adapter and Object Adapter

Click here https://www.ciol.com/images/adapter.gif
to view the image

Advertisment

Sample Code

Advertisment

/*

EXAMPLE-1

In a Class Adapter pattern, Adapter extends the Adaptee. When the
adapter is used in client code, it works as a Hashtable and gives get
("X") function signature.

Advertisment

The class adapter is supposed to extend the Target as well, but Java doesn’t
support multiple inheritance, which is achieved by using multiple interface
implementation. In this case, we can implement Map interface that Hashtable
implements. But for simplicity we have ignored the implementation of the
interface.

*/

class myAdapter extends Adaptee

{

Hashtable variables = new Hashtable( 20);

public myAdapter()

{

// calling methods of parent class i.e. the Adaptee

variables.put( "AUTH_TYPE" , getAuthType());

variables.put( "REMOTE_USER", getRemoteUser());

//other methods

}

public Object get(Object key)

{

return variables.get( key );

}

//other methods

}

/*

This is an object adapter, where myAdapter is the Adapter, ‘Adaptee’ is
the adaptee and Hashtable is the Target. The Adapter delegates the
responsibilities to an adaptee to get the values.

*/

class myAdapter extends Hashtable

{

Hashtable variables = new Hashtable(20);

// composition of an object

public myAdapter( Adaptee adaptee )

{

variables.put( "AUTH_TYPE" , adaptee.getAuthType());

variables.put( "REMOTE_USER" , adaptee.getRemoteUser());

//other methods

}

public Object get(Object key)

{

return variables.get( key );

}

//other methods

}

/*

EXAMPLE — 2

Here we have adapted one Local class here to make that remotely
available. The local class neither extends UnicastRemoteObject nor its
operations throw RemoteException as required by java RMI specification. So we
have defined an Adapter class that wraps around the Local class and also
conforms to RMI specification to be remotely available.

Java doesn’t support multiple inheritance. But the Remote class must extend
UnicastRemoteObject class. So it is not possible to extend the Adaptee class in
our example. So we have adapted Object Adapter here. But this design conforms to
the basic Design principle of favoring Composition to Inheritance.

*/

//Adaptee Class which is a local class

class CustomerInfo{

private int custId;

private float salary;

public float getSalary(int custId){

/*

Write code here to fetch salary from database

it is hardcoded here to Rs. 1000 for simplicity

*/

salary=1000;

return salary;

}

}

// Declare the Remote Interface

interface IRemoteCustomerInfo extends java.rmi.Remote{

/*

All remote methods throw java.rmi.RemoteException as part of

java RMI requirement.

*/

public float getSalary(int custId) throws java.rmi.RemoteException;

}

// Adapter class that adapts a local class to a remote implementation

public class RemoteCustomerInfoAdapter extends
java.rmi.server.UnicastRemoteObject

implements IRemoteCustomerInfo{

protected CustomerInfo adaptee;

public RemoteCustomerInfoAdapter(CustomerInfo customerInfo)

throws java.rmi.RemoteException{

		this.adaptee=adaptee;

}

public float getSalary(int custId) throws java.rmi.RemoteException{

return adaptee.getSalary(custId);

}

}		

RemoteCustomerInfoAdapter is now ready for use as a Remote class.

Complexities simplified

Pluggable Adapters

In Example-1 we adapted a class with getX() methods to a
Hashtable interface. It is likely that we may adapt another class with getX()
methods to a Hashtable in the future. It would be appropriate to write one class
to do all such adapting. Pluggable adapter Adapter adapts dynamically to one of
the adapters. Adapter decides which class it adapts based on parameters or
differing constructors.

Two-way Adapters

Two-way Adapters are more transparent to the clients than one-way
Adapters as they conform to the interfaces of both Adaptee and Target. So the
client can use both the interfaces with the same Adapter class without knowing
anything about the Adaptee. We can do that in Example-1 by providing both getX()
and get("X") interfaces.

Also Known as and Related Patterns

This pattern is also known as Wrapper.

Bridge has similar structure as an object adapter, but it has a different
intent of separating the interface from the implementation.

Decorator enhances an object’s responsibility dynamically without
changing the interface and hence more transparent than Adapters.

Proxy defines a representation for another object without changing its
interface.

tech-news