Friday, February 28, 2014

Structural Design Pattern : Adapter design pattern



Adapter design pattern talks about Convert the existing interfaces to a new interface to achieve compatibility and re usability of the unrelated classes in one application  also known as Wrapper pattern


“A class converts the interface of one class to be what another class expects.”
 
In real world we have adapters for power supplies, adapters for camera memory cards, and so on.
The Adapter pattern is used so that two unrelated interfaces can work together. The joining between them is called an Adapter. This is something like we convert interface of one class into interface expected by the client. We do that using an Adapter.
An adapter allows classes to work together that normally could not because of incompatible interfaces, by providing its interface to clients while using the original interface
 

It comprises three components:
  • Target: This is the interface with which the client interacts.
  • Adaptee: This is the interface the client wants to interact with, but can’t interact without the help of the Adapter.
  • Adapter: This is derived from Target and contains the object of Adaptee.

There are 2 ways to implement Adapter 1) Inheritance 2) Composition 




1) Inheritance: Class Adapters - Based on (Multiple) Inheritance


In the language supporting inheritance we can use this.  here we can extends the Adaptee .  The adapter class which is inherited will have new compatible methods. Using those new methods from the adapter the core function of the base class will be accessed. This is called “is-a” relationship.
  • It adapts the specific Adaptee class. The class it extends. If that one is subclassed it can not be adapted by the existing adapter.
  • It doesn't require all the code required for delegation, which must be written for an Object Adapter.
 

1:  public class CylindricalSocket {  
2:   public String supply(String cylinStem1, String cylinStem1) {  
3:    System.out.println("Power power power...");  
4:    return "I got power";  
5:   }  
6:  }  


1:  public class RectangularAdapter extends CylindricalSocket {  
2:   public String adapt(String rectaStem1, Sting rectaStem2) {  
3:    //some conversion logic  
4:    String cylinStem1 = rectaStem1;  
5:    String cylinStem2 = rectaStem2;  
6:    return supply(cylinStem1, cylinStem2);  
7:   }  
8:  }  



1:  public class RectangularPlug {  
2:   private String rectaStem1;  
3:   private String rectaStem2;  
4:   public getPower() {  
5:    RectangulrAdapter adapter = new RectangulrAdapter();  
6:    String power = adapter.adapt(rectaStem1, rectaStem2);  
7:    System.out.println(power);  
8:   }  
9:  }  





This type of adapter uses multiple polymorphic interfaces to achieve its goal. The adapter is created by implementing or inheriting both the interface that is expected and the interface that is pre-existing. It is typical for the expected interface to be created as a pure interface class, especially in languages such as Java that do not support multiple inheritance



2) Composition  (Objects Adapters - Based on Delegation)

 :   Instead of inheriting the base class create adapter by having the base class as attribute inside the adapter. You can access all the methods by having it as an attribute. This is nothing but “has-a” relationship. Following example illustrates this approach. Difference is only in the adapter class and other two classes are same. In most scenarios, prefer composition over inheritance. Using composition you can change the behavior of class easily if needed. It enables the usage of tools like dependency injection.

Objects Adapters are the classical example of the adapter pattern. This behavior gives us a few advantages over the class adapters
The main disadvantage is that it requires to write all the code for delegating all the necessary requests tot the Adaptee.

In this type of adapter pattern, the adapter contains an instance of the class it wraps. In this situation, the adapter makes calls to the instance of the wrapped object.



1:  public class CylindricalSocket {  
2:   public String supply(String cylinStem1, String cylinStem1) {  
3:    System.out.println("Power power power...");  
4:   }  
5:  } 

 

1:  public class RectangularAdapter {  
2:   private CylindricalSocket socket;  
3:   public String adapt(String rectaStem1, Sting rectaStem2) {  
4:    //some conversion logic  
5:    socket = new CylindricalSocket();  
6:    String cylinStem1 = rectaStem1;  
7:    String cylinStem2 = rectaStem2;  
8:    return socket.supply(cylinStem1, cylinStem2);  
9:   }  
10:  }  





Adapter design pattern in java API

java.io.InputStreamReader(InputStream)
java.io.OutputStreamWriter(OutputStream)

Notes : 
1)    Adapter Pattern and Strategy Pattern - there are many cases when the adapter can play the role of the Strategy Pattern. If we have several modules implementing the same functionality and we wrote adapters for them, the adapters are implementing the same interface. We can simply replace the adapters objects at run time because they implements the same interface.
2)    Adapter makes things work after they're designed; Bridge makes them work before they are.
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.
6)    Adapter is meant to change the interface of an existing object. Decorator enhances another object without changing its interface. 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.
 



No comments: