CHAPTER 8

image

Adapter Patterns

GoF Definition: Convert the interface of a class into another interface that clients expect. The adapter pattern lets classes work together that couldn’t otherwise because of incompatible interfaces.

Concept

The core concept is best described by the examples given below.

Real–Life Example

The most common example of this type can be found with mobile charging devices. If our charger is not supported by a particular kind of switchboard, we need to use an adapter. Even the translator who is translating language for one person is following this pattern in real life.

Computer World Example

In real-life development, in many cases, we cannot communicate between two interfaces directly. They contain some kind of constraint within themselves. To deal with this kind of incompatibility between those interfaces, we may need to introduce adapters.

A very common use of this pattern is illustrated below.

Illustration

In this example, we can calculate the area of a rectangle easily. If we see the Calculator class and its getArea() method, we’ll know that we need to supply a rectangle as an input in the getArea() method to get the area of the rectangle. Now suppose we want to calculate the area of a triangle, but we need to get the area of the triangle through the getArea() method of Calculator. How can we do that?

To do that we have made a CalculatorAdapter for the triangle and passed a triangle in its getArea() method. The method will translate the triangle input to rectangle input and in turn, it will call the getArea() of Calculator to get the area of it. But from the user’s point of view, it is very simple: it seems to the user that he/she is passing a triangle to get the area of that triangle.

UML Class Diagram

9781484218013_unFig08-01.jpg

Package Explorer view

High-level structure of the parts of the program is as follows:

9781484218013_unFig08-02.jpg

Implementation

package adapter.pattern.demo;
class Rect
    {
        public double l;
        public double w;
    }
class Triangle
{
    public double b;//base
    public double h;//height
    public Triangle(int b, int h)
    {
        this.b = b;
        this.h = h;
    }
}
/*Calculator can calculate the area of a rectangle. To calculate the area we need a Rectangle input.*/
class Calculator
{   Rect rectangle;
        public double getArea(Rect r)
        {
                rectangle=r;
                return rectangle.l * rectangle.w;
        }
}

/*Calculate the area of a Triangle using CalculatorAdapter. Please note here: this time our input is a Triangle.*/
class CalculatorAdapter
{
        Calculator calculator;
        Triangle triangle;
        public double getArea(Triangle t)
        {
                calculator = new Calculator();
                triangle=t;
                Rect r = new Rect();
                //Area of Triangle=0.5*base*height
                r.l = triangle.b;
                r.w = 0.5*triangle.h;
                return calculator.getArea(r);
        }

}

public class AdapterPattern
{
        public static void main(String[] args)
        {
                System.out.println("***Adapter Pattern Demo***");
                CalculatorAdapter cal=new CalculatorAdapter();
                Triangle t = new Triangle(20,10);
                System.out.println(" Adapter Pattern Example ");
                System.out.println("Area of Triangle is :" + cal.getArea(t));
        }
}

Output

9781484218013_unFig08-03.jpg

Note

GoF tells us about two major kinds of adapters:

  1. Class adapters. They generally use multiple inheritance to adapt one interface to another. (But we must remember, in Java, multiple inheritance through classes is not supported. We need interfaces to implement the concept of multiple inheritance.)
  2. Object adapters. They depend on the object compositions.

    To illustrate the concepts, I’ll present a simple example for your ready reference:

9781484218013_unFig08-04.jpg

Illustration

package different.type.adapter;
interface IIntegerValue
{
        public int getInteger();

}
class IntegerValue implements IIntegerValue
{
        @Override
        public int getInteger()
        {
                return 5;
        }
}
class ClassAdapter extends IntegerValue
{
        //Incrementing by 2
        public int getInteger()
        {
                return 2+super.getInteger();
        }
}
class ObjectAdapter
{
        private IIntegerValue myInt;
        public ObjectAdapter(IIntegerValue myInt)
        {
                this.myInt=myInt;
        }
        //Incrementing by 2
        public int getInteger()
        {
                return 2+this.myInt.getInteger();
        }

}

class ClassAndObjectAdapter
{
        public static void main(String args[])
        {
                System.out.println("***Class and Object Adapter Demo***");
                ClassAdapter ca1=new ClassAdapter();
                System.out.println("Class Adapter is returning :"+ca1.getInteger());

                ClassAdapter ca2=new ClassAdapter();
                ObjectAdapter oa=new ObjectAdapter(new IntegerValue());
                System.out.println("Object Adapter is returning :"+oa.getInteger());
        }
}

Output

9781484218013_unFig08-05.jpg

To what extent does an adapter need to take care when it adapts an adaptee?

It depends on that particular case. If our target interface is very similar, then adapters do not have much work. If there is not much similarity, then adapters must do some extra work to match those functionalities.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.15.43