Wednesday, March 2, 2011

Adapter pattern / Wrapper pattern

Adapter Pattern converts interface of a class into another interface that client expects. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
This pattern is also known as Wrapper pattern.


Example in Real life


British plugs OR Indian plugs are cylindrical and American plugs are recangularish. You can use an adapter in between to fit an American (rectangular) plug in British (cylindrical) socket assuming voltage requirements are met with.


Types of Adapters
There are two kinds of adapters( base on composition vs inheritance).
1. Object Adapters (based on composition )
2. Class Adapters(based on inheritance)

Adapter pattern using composition


Object Adapters : Object Adapters use a compositional technique to adapt one interface to another. The adapter inherits the target interface that the client expects to see, while it holds an instance of adaptee. Object adapters enable the client and the adaptee to be completely decoupled from eachother. Only the adapter knows about both of them.

Before going deeper let us have a simple example.
Consider the scenario where our legacy code that exposes the Enumerator interface, but we want our new code to only use iterators.

Here EnumerationIterator is our Adapter.
As we know Enumerator does not support remove(). There is no way to implement a fully functioning remove() method on the adapter. So let us try to throw RunTimeException. As we know remove() method in Iterator throws Unsupported Operation Exception. As long as client is careful (watchout for potential exceptions) and the adapter is well documented it is perfectly reasonable solution.
/*
 *  We are Adapting Enumeration to Iterator.
 *  Adapter EnumeratorIterator implements Iterator to look like an Iterator 
 */

public class EnumeratorIterator implements Iterator{
    Enumeration enumeration;

   public EnumeratorIterator(Enumeration enumeration){
     this.enumeration = enumeration;
   }

// Iterator's hasNext() method is delegated to Enumerator's hasMoreElements()
   public boolean hasNext(){
     return enumeration.hasMoreElements();
   }

   // Iterator's next() method is delegated to Enumerator's nextElement()
   public Object next(){
     return enumeration.nextElement();
   }

   public void remove(){
     throw new UnsupportedOperationException();
   }
}


How can Client use Adapter:
1. The Client makes a request to the adapter by calling a method on it using the target interface.
2. The Adapter translates that request into one or more calls on adaptee using adaptee interface.
3. The client receives the result of the call and never knows there is an adapter doing the translation.


Adapter Pattern using inheritance

Class Adapters : Class adapters use multiple inheritance to achieve their goals. As in the object adapter, the class adapter inherits the interface of the client's target. However, it also inherits the interface of the adaptee as well. Since Java does not support true multiple inheritance, this means that one of the interfaces must be inherited from a Java Interface type. Note that either or both of the target or adaptee interfaces could be an Java Interfaces. The request to the target is simply rerouted to the specific request that was inherited fro the adaptee interface.

Differnce between Object Adapters and Class Adapters
1. As Object Adapter uses composition it can not only adapt an adaptee class, but any of its subclasses. It is flexible.
2. Class Adapter is commited to only one adaptee. But again it has an advantage as no need to implement the entire adaptee. It can just override the behaviour of adaptee and also can override the behaviour as it is subclassing.
3. Note that class adapters have a problem with name conflicts if methods of the same signature exist on both the target and the adaptee. Note that just because two objects have methods that have the same signature (syntax), it does not guarantee that the two methods have the same meaning or behavior (sematics). That is, the two methods do not necessarily map directly to each other. Object adapters do not have this problem.
4. Class adapters are simpler than object adapters in that they involve fewer classes and are useful if total decoupling of the client and adaptee is not needed.

Why should I use Adapter Pattern:
1. Sometimes a toolkit or class library can not be used because its interface is incompatible with the interface required by an application.
2. We can not change the library interface, since we may not have its source code.
3. Even if we did have the source code, we probably should not change the library for each domain-specific application.
4. You don’t want your object models implementing JavaVM specific interfaces becuase they might change in the future.
When to use Adapter Pattern:
Use the Adapter pattern when
1. You want to use an existing class, and its interface does not match the one you need.
2. You want to create a reusable class that cooperates with unrelated classes with incompatible interfaces.

Some of the good OO design principles behind Adapter Pattern:
1. We use object composiition to wrap adaptee with an altered interface. This approach has an added advantage that we can use an adapter with any subclass of adaptee.
2. Pattern binds the client to an interface but not to implementation. We could use several adapters, each converting a different backend set of classes or we could add new implementations after the fact, as long as they adhere to target interface.

Two-way Adapter
A two-way adapter supports both the Target and the Adaptee interface. It allows an adapted object (Adapter) to appear as an Adaptee object or a Target object.
One way to implement two-way adapters is to use multiple inheritance, which can't be done in Java.
But we can have our adapter class implement two different Java interfaces. So the adapter can act as a Old Interface or New Interface.

Comparing Adapter Pattern with other Patterns:
1. Adapter converts one interface to another, Decorator doesn't alter interface but adds responsibility. Facade makes an interface simpler.
Decorator is thus more transparent to the application than an adapter is. As a consequence, Decorator supports recursive composition, which isn't possible with pure Adapters.
2. Adapters allows client to make use of libraries and subsets without changing any code. Decorators allow new behaviour to be added to the classes with out altering the existing code.
3. Adapter make things work after they're designed, Bridge makes them work before they are.
4. Bridge is designed up-front to let the abstraction and the implementation vary independently. Adapter is retrofitted to make unrelated classes work together.
5. Adapter provides a different interface to its subject. Proxy provides the same interface. Decorator provides an enhanced interface.
6. Facade defines a new interface, whereas Adapter reuses an old interface. Remember that Adapter makes two existing interfaces work together as opposed to defining an entirely new one.

Adapter pattern example in java
java.io.InputStreamReader(InputStream)
java.io.OutputStreamWriter(OutputStream)

No comments:

Post a Comment

Chitika