Adapter Design Pattern in Java

Reading Time: 4 minutes

Contents

Description

Adapter Design pattern is listed underneath the Structural patterns. As you understand from the name it is designated to act like an adapter. When you look for this pattern there are different descriptions and examples, however I find the below illustration very clear what the pattern stands for;

Adapter Pattern Illustration

As you study the illustration we see three elements here;

  • Client: Expects to work with the Adaptee, however it is not compatible with the client,
  • Adapter: Wraps the Adaptee’s logic and provides a way to utilize adaptee,
  • Adaptee: An interface or an abstract class that has legacy methods which are not compatible with the client.

The stand point of the pattern is to work the clients with the incompatible interfaces by not chancing or enhancing the methods of the adaptee via the Adapter classes/interfaces. On the other hand also Adapters known as a Wrapper classes. Furthermore, the adapter pattern also practices the Open Close principle in the S.O.L.I.D. in a way that we will not change the existing code unit that will be closed, however we will wrap it by using an adapter. In the real world examples you will see US/Europe electricity socket voltage adapters and all in one memory card, card reader a computer and so on.

Last of all the Adapter Pattern may have some similarities to;

  • Façade Pattern: It provides a simple interface and methods for complex structure,
  • Decorator Pattern: Enhances an interface and adds more functionalities

However, the Adapter pattern does neither of those, but provides a way to the client to work with an incompatible interface by either encapsulating the logic or delegating it. Observe the following to apprehend the topic.

Forming the Pattern

The adapter pattern can be form in two different ways;

Class Adapter

Adapter pattern class adapter uml diagram

The adapter class utilizes Inheritance. The Adapter implement/extends the Adaptee interface/abstract class and overrides the methods,

Object Adapter

adapter pattern object adapter uml diagram

The adapter class utilizes Composition. The adapter has an instance of the Adaptee interface/abstract class and delegates the request to it.

 

Example

For the sake of the simplicity, I’ll emphasis on an old main frame that needs an adapter for classes that work on the Strings with tabs after each enter.

The objects and the roles we have:

  • MainFrameSender: it is the main interface that has we will wrap, it only accepts a String as a parameter
  • MainFrameSenderImpl: it is the implementation of the Main Frame interface,
  • ClassMainFrameSenderAdapter: The adapter class that is formed with the Class Adapter format.The Adapter will convert the Content object into the String that the interface accepts,
  • ObjectMainFrameSenderAdapter: The adapter class that is formed with the ObjectAdapter format. The Adapter will convert the Content object into the String that the interface accepts,
  • Content: This is the Pojo class that will be used to carry the data by the clients,
  • Main: It is used as a client and expose the capabilities of the each adapter implementation.

MainFrameSender.java

public interface MainFrameSender {
    void sendToMainFrame(String content);
}

MainFrameSenderImpl.java

public class MainFrameSenderImpl implements MainFrameSender {
    @Override
    public void sendToMainFrame(String content) {
        System.out.println("sending the content to the mainframe: " + content);
    }
}

ClassMainFrameSenderAdapter.java

public class ClassMainFrameSenderAdapter implements MainFrameSender {

    @Override
    public void sendToMainFrame(String content) {
        System.out.println("sending the content to the mainframe: " + content);
    }

    public void sendToMainFrame(Content content) {
        final StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(content.getMessageId());
        stringBuilder.append("\t");
        stringBuilder.append(content.getHeader());
        stringBuilder.append("\t");
        stringBuilder.append(content.getContent());
        sendToMainFrame(stringBuilder.toString());
    }
}

ObjectMainFrameSenderAdapter.java

public class ObjectMainFrameSenderAdapter {

    private MainFrameSender mainFrameSender = new MainFrameSenderImpl();

    public void sendToMainFrame(Content content) {
        final StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(content.getMessageId());
        stringBuilder.append("\t");
        stringBuilder.append(content.getHeader());
        stringBuilder.append("\t");
        stringBuilder.append(content.getContent());
        mainFrameSender.sendToMainFrame(stringBuilder.toString());
    }
}

Content.java

public final class Content {
    private int messageId;
    private String header;
    private String content;

    public Content(int messageId, String header, String content){
        this.messageId=messageId;
        this.header=header;
        this.content=content;
    }

    public int getMessageId(){
        return messageId;
    }

    public String getHeader(){
        return header;
    }

    public String getContent(){
        return content;
    }

    @Override
    public String toString() {
        return "Content{" +
                "messageId=" + messageId +
                ", header='" + header + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        Content content = new Content((int)Math.random(), "Message 1","this message sent via Class Adapter");
        MainFrameSender classMainFrameSenderAdapter = new ClassMainFrameSenderAdapter();
        ((ClassMainFrameSenderAdapter) classMainFrameSenderAdapter).sendToMainFrame(content);

        Content content2 = new Content((int)Math.random(), "Message 2","this message sent via Object Adapter");
        ObjectMainFrameSenderAdapter objectMainFrameSenderAdapter = new ObjectMainFrameSenderAdapter();
        objectMainFrameSenderAdapter.sendToMainFrame(content2);
    }
}

Console Output

sending the content to the mainframe: 0	Message 1	this message sent via Class Adapter
sending the content to the mainframe: 0	Message 2	this message sent via Object Adapter