Advertisment

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