Sunday, March 26, 2023

Adapter Design Pattern in Java

 

The Adapter pattern is a design pattern in Java that allows two incompatible interfaces to work together. It is used when two classes with incompatible interfaces need to work together, or when an existing class needs to work with new functionality that cannot be easily integrated.

The Adapter pattern works by creating a new class that acts as a bridge between the two incompatible interfaces. This new class, known as the adapter, implements the interface of the client code and wraps the interface of the legacy code, translating the calls between the two interfaces.

 Here is an example of how the Adapter pattern can be implemented in Java:

Suppose we have a legacy class that provides an interface to print a message to the console:

public class LegacyPrinter {
    public void print(String message) {
        System.out.println(message);
    }
}

Now suppose we have a new client class that needs to print a message to the console using a different interface:

public interface Printer {
    void printMessage(String message);
}

To use the LegacyPrinter with the Printer interface, we can create an adapter class that implements the Printer interface and wraps the LegacyPrinter:

public class LegacyPrinterAdapter implements Printer {
    private LegacyPrinter legacyPrinter;

    public LegacyPrinterAdapter(LegacyPrinter legacyPrinter) {
        this.legacyPrinter = legacyPrinter;
    }

    @Override
    public void printMessage(String message) {
        legacyPrinter.print(message);
    }
}

Now the client code can use the Printer interface to print messages to the console, even though it is using the LegacyPrinter behind the scenes:

public class Client {
    public static void main(String[] args) {
        Printer printer = new LegacyPrinterAdapter(new LegacyPrinter());
        printer.printMessage("Hello, World!");
    }
}

In this example, the LegacyPrinterAdapter acts as a bridge between the Printer interface and the LegacyPrinter interface, allowing the client code to use the Printer interface to print messages to the console using the LegacyPrinter.

 Types of Adapter design patterns

1) Class Adapter pattern

Class Adapter pattern: The Class Adapter pattern uses inheritance to adapt one interface to another. In this pattern, the adapter class extends the existing class that provides the legacy interface, and also implements the new interface that the client code expects. The adapter class translates the calls from the new interface into calls to the existing class. 

In the Class Adapter pattern, we use inheritance to adapt the legacy interface to the target interface. Here's an example:

Legacy Interface:

public class LegacyRectangle {
    public void draw(int x, int y, int width, int height) {
        System.out.println("Drawing Rectangle [" + x + "," + y + "," + width + "," + height + "]");
    }
}

Target Interface:

 public interface Shape {
    void draw(int x1, int y1, int x2, int y2);
}

Adapter class:

public class RectangleAdapter extends LegacyRectangle implements Shape {

    @Override
    public void draw(int x1, int y1, int x2, int y2) {
        int x = Math.min(x1, x2);
        int y = Math.min(y1, y2);
        int width = Math.abs(x2 - x1);
        int height = Math.abs(y2 - y1);
        super.draw(x, y, width, height);
    }
}

Client Code:

public class Client {
    public static void main(String[] args) {
        Shape shape = new RectangleAdapter();
        shape.draw(10, 20, 30, 40);
    }
}

In this example, we created a RectangleAdapter class that extends the LegacyRectangle class and implements the Shape interface. The adapter class adapts the draw() method of the LegacyRectangle class to the draw() method of the Shape interface. The client code can now use the Shape interface to draw a rectangle, even though the underlying implementation uses the LegacyRectangle class.

2) Object Adapter pattern

The Object Adapter pattern uses composition to adapt one interface to another. In this pattern, the adapter class contains an instance of the existing class that provides the legacy interface, and also implements the new interface that the client code expects. The adapter class translates the calls from the new interface into calls to the existing class by delegating the calls to the contained object. 

In the Object Adapter pattern, we use composition to adapt the legacy interface to the target interface. Here's an example:

Legacy Interface:

public class LegacyLine {
    public void draw(int x1, int y1, int x2, int y2) {
        System.out.println("Drawing Line [" + x1 + "," + y1 + "] to [" + x2 + "," + y2 + "]");
    }
}

Target Interface

public interface Shape {
    void draw(int x1, int y1, int x2, int y2);
}

Adapter class:

public class LineAdapter implements Shape {

    private LegacyLine legacyLine;
    public LineAdapter(LegacyLine legacyLine) {
        this.legacyLine = legacyLine;
    }
    @Override
    public void draw(int x1, int y1, int x2, int y2) {
        legacyLine.draw(x1, y1, x2, y2);
    }
}

Client code:

public class Client {
    public static void main(String[] args) {
        LegacyLine legacyLine = new LegacyLine();
        Shape shape = new LineAdapter(legacyLine);
        shape.draw(10, 20, 30, 40);
    }
}

In this example, we created a LineAdapter class that implements the Shape interface and contains an instance of the LegacyLine class. The adapter class adapts the draw() method of the LegacyLine class to the draw() method of the Shape interface by delegating the call to the contained object. The client code can now use the Shape interface to draw a line, even though the underlying implementation uses the LegacyLine class. 

The real JDK examples are well explained in below post

Examples Of Adapter Design Pattern in JDK

 

 


augustine

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.

0 comments:

Post a Comment

 

Copyright @ 2013 Java Tutorial.

Designed by Mathew | mathai