Saturday, April 16, 2011

Adapter 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

Motivation:
Sometimes a toolkit or class library or a third party jars can not be used because its interface is
Incompatible with the interface required by an application
We can not change the library interface, since we may not have its source code. Even if we did have the source code, we should not change the library for each domain-specific application.
Adapter Pattern at First Glance:
Shown below are Gas cylinder and a rubber pipe. Both are incompatible and cannot be connected.
Now it’s a big problem?
How to Connect them?
 You will definitely know the solution to this. Yes a gas Regulator. We are familiar with this because we use it in our day to day life. Adapter Pattern is also very simple to understand.
Regulator is our soultion

Kudos this is the solution and our problem is solved. Now we can start cooking food.
Fix the regulator to cylinder and put the pipe
Another Example is shown in the below figures.

These are two incompatible interfaces lets see the solution for this.

Lets observe another real time example which we are using daily, it will also give us a better insight of Adapter Pattern.
  
Let us try out Some Coding
We have two interfaces Horse and Zebra.
  
public interface Horse {

      public void runningStyle(String s);

      public void mySkinColor(String s);

}

public interface Zebra {

      public void mySkinColor(String s);

      public void walkingStyle(String s);

}

Now we have implementations of Horse and Zebra as Racing Horse and PetZebra respectively.
Racing Horse and Pet Zebra
  
  
public class RacingHorse implements Horse {

      public void runningStyle(String s) {
            System.out.println(s);
      }

      public void mySkinColor(String s) {
            System.out.println(s);
      }
}

public class PetZebra implements Zebra {

      public void walkingStyle(String s) {
            System.out.println(s);
      }

      public void mySkinColor(String s) {
            System.out.println(s);
      }

}
  
One day a lot of Kids visit our Stable and ask to have a Horse race but we don’t have that many horses in our stable as the total number of students. We requested the kids to race in different groups but they did not agree and started screaming. Let’s see how the stable owner comes out of this problem.
He knows a bit of design Patterns and Java so decided to write and adapter for a zebras. This is how the adapter looked like. 
Zebra converted to Horse

  
public class ZebraAdapter implements Horse {

      /**
       * Adaptee
       */
      Zebra zebra;

      public ZebraAdapter(Zebra zebra) {
            this.zebra = zebra;
      }

      public void runningStyle(String s) {
            zebra.walkingStyle(s);
      }

      public void mySkinColor(String s) {
            zebra.mySkinColor(s);
      }
}



It’s the time to test if Zebras can be behave like Horses in a race.
public static void main(String[] args) {
      /**
       * Horse Type
       */
      RacingHorse rh = new RacingHorse();

      rh.mySkinColor("Racing Horse is Brown in color");
      rh.runningStyle("Racing Horse runs 100 Kms/Hr");

      /**
       * Zebra Type
       */
      PetZebra pz = new PetZebra();

      pz.mySkinColor("Pet Zebra has Black and White Stripes");
      pz.walkingStyle("Pet Zebra run 30 Kms/Hr");

      /**
       * Adapter to make Zebra to a Horse
       */
      Horse za = new ZebraAdapter(pz);
      za.mySkinColor("Remove my Stripes and Paint me Brown");
      za.runningStyle("Give me some Horse Power to run 100 Kms/Hr");
      }

}

Output:
Racing Horse is Brown in color
Racing Horse runs 100 Kms/Hr

Pet Zebra has Black and White Stripes
Pet Zebra run 30 Kms/Hr

Remove my Stripes and Paint me Brown
Give me some Horse Power to run 100 Kms/Hr

Hurray we see that our zebras now looks and runs like a Horse. Kids you can have a race now.

Its Racing Time

Two kinds of adapters:

1. Object Adapters: An object adapter relies on object composition
2. Class Adapters: A class adapter uses multiple inheritance to adapt one interface to another

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 each other. Only the adapter knows about both of them.


Class Adapters: Class adapters use multiple inheritance to achieve their goals. The class adapter inherits both the client’s target and adaptee interface 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 a Java Interfaces. The request to the target is simply rerouted to the specific request that was inherited fro the adaptee interface.


How can Client use Adapter:

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


Difference between Object Adapters and Class Adapters:

As Object Adapter uses composition it can not only adapt an adaptee class, but any of its subclasses.So it is flexible.

 Class Adapter is committed to only one adaptee. But again it has an advantage as no need to implement the entire adaptee. It can just override the behavior of adaptee and also can override the behavior as it is subclassing.

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 (semantics). Object adapters do not have this problem.

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.



When to use Adapter Pattern:

Use the Adapter pattern when :

  •       It's quite useful when dealing with the legacy code especially that was written a while ago and to which one might not have access.
  •     It is especially useful for off-the-shelf code, for toolkits, for libraries or any third party software.
  •       You want to create a reusable class that cooperates with unrelated classes with incompatible interfaces.

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.

We can have our adapter class implement two different interfaces. So the adapter can perform both the transitions depending on some criteria

Comparing Adapter Pattern with other Patterns:

This section will be useful for people who already know various patterns like Proxy, Façade, Bridge and Decorator

   1.    Adapter converts one interface to another, Decorator doesn't alter interface but adds    responsibility. Facade makes an interface simpler.
   2.    Adapters allows client to make use of libraries and subsets without changing any code. Decorators allow new behavior to be added to the classes with out altering the existing code.
   3.    Bridge is designed up-front to let the abstraction and the implementation vary independently. Adapter is retrofitted to make unrelated classes work together. 
   4.    Adapter provides a different interface to its subject. Proxy provides the same interface. Decorator provides an enhanced interface.
   5.    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.