Adapter Design Pattern in Java

Reading Time: 4 minutes

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

Mediator Design Patter in Java

Reading Time: 4 minutes

Definition

The Mediator Pattern falls into the Behavioral Pattern. In simple terms, there is centrally a mediator that handles communication between object in a loosely coupled way, thus objects shall not talk to each other directly. Furthermore, often developers get confused with the Observer pattern, and they seem pretty similar. However, we can break the ultimate difference down like this:

  • Observer Pattern: The objects are not interested in each other, so the relationship is one-to-many, many objects are interested in the state change of one object,
  • Mediator Pattern: The objects are interested to interact with many other objects, so the relation is many to many.

To better understand the deal in the Mediator pattern please study the below illustration;

Before The Mediator Pattern Applied

After The Mediator Pattern Applied

Rules of the Pattern

In this pattern there are two components that we need to create and mind;

Colleagues: These objects are primarily the targets that will not talk to each other directly and have the same base type abstract class or interface that will inherit the same attributes. Furthermore, they will have have the knowledge of the mediator component, which means that each of them will have access an instance to the mediator pattern, rather than having instances to other colleague objects.

Mediator: The centralized component that manages the communication between colleague components.

Example Code Snippet

To better understand the concept, I have developed a simple HR Organization suite. Here the HR is the mediator that knows all the participant Organization units and handles the communication between the Organization components. Then last of all we have the Organization base type that has all the common attributes, Manager and Employee objects are the child classes for the organization, they are separated and have their own functions. The communication is eliminated.

You will see some actions;

  • Registration: A new organization type is created, then it is instantly registered in the HR list,
  • Announcement: HR makes the announcement to all the whole organization regardless of the Organization instance is Manager or Employee,
  • Initiation of the Resignation: Here when an employee resigns, the employee will not talk to the Manager directly, but HR that initiates the process and talks to the Manager,
  • Surprise Party Preparation: After the resignation process is approved by the manager, the HR throws a surprise party without notifying the resigning employee and makes an announcement to the whole Organization.

HR.java

public interface HR {
    void registerOrganization(Organization organization);
    void makeAnnouncementToOrganization(final String message);
    void initiateResignationProcess(Organization employee, Organization manager);
}

HRImplementation.java

import java.util.HashSet;
import java.util.Set;

public class HRImplementation implements HR {
    private final Set<Organization> listOfOrganization = new HashSet<Organization>();

    @Override
    public void registerOrganization(Organization organization) {
        listOfOrganization.add(organization);
    }

    @Override
    public void makeAnnouncementToOrganization(String message) {
        System.out.println("Making announcement to the whole organization");
        for (Organization organization : listOfOrganization) {
            organization.receiveAnnouncement(message);
        }
    }

    @Override
    public void initiateResignationProcess(Organization employee, Organization manager) {
        System.out.println("Employee " + employee.getName() + " would like to resign from the company");
        System.out.println("HR is notifying the manager");
        boolean managerResponse = ((Manager) manager).decideAndFinalizeResignation(employee);
        if (managerResponse) {
            System.out.println(manager.getName() + " has approved " + employee.getName() + "\'s resignation") ;
            prepareSurpriseParty(employee);
        }
    }

    private void prepareSurpriseParty(Organization resigningEmployee) {
        System.out.println("Preparing the surprise party for " + resigningEmployee.getName());
        for (Organization organization : listOfOrganization) {
            if (organization != resigningEmployee)
                organization.receiveAnnouncement("Guys " + resigningEmployee.getName() + " is resigning his position, and you " + organization.getName() + " are invited to his surprise party");
        }
    }
}

Organization.java

public abstract class Organization {
    private final HR hr;
    private final String name;

    public Organization(HR hr, String name) {
        this.hr = hr;
        this.name = name;
        this.hr.registerOrganization(this);
    }

    public void receiveAnnouncement(final String message) {
        System.out.println(this.getClass().getSimpleName() + " " + name + " received the announcement " + message);
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Organization that = (Organization) o;

        return name.equals(that.name);
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }
}

Manager.java

public class Manager extends Organization {
    private HR hr;
    private String managerName;

    public Manager(HR hr, String name) {
        super(hr, name);
        this.hr = hr;
        this.managerName = name;
    }

    public boolean decideAndFinalizeResignation(Organization employee) {
        System.out.println("Manager " + managerName + " is considering " + employee.getName() + "\'s resignation");
        return true;
    }
}

Employee.java

public class Employee extends Organization {
    private HR hr;
    private String employeeName;

    public Employee(HR hr, String name) {
        super(hr, name);
        this.hr = hr;
        this.employeeName = name;
    }

    public void giveResignation(Organization manager){
        System.out.println("Employee " + employeeName + " would like to resign");
        hr.initiateResignationProcess(this, manager);
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        HR hr = new HRImplementation();
        Organization konrad = new Manager(hr, "Konrad");
        Organization tugrul = new Employee(hr, "Tugrul");
        Organization oguz = new Employee(hr, "Oguz");
        Organization altan = new Employee(hr, "Altan");

        hr.makeAnnouncementToOrganization("Welcome guys :)");
        ((Employee) tugrul).giveResignation(konrad);
    }
}

Console Output

Making announcement to the whole organization
Manager Konrad received the announcement Welcome guys 🙂
Employee Altan received the announcement Welcome guys 🙂
Employee Oguz received the announcement Welcome guys 🙂
Employee Tugrul received the announcement Welcome guys 🙂
Employee Tugrul would like to resign
Employee Tugrul would like to resign from the company
HR is notifying the manager
Manager Konrad is considering Tugrul’s resignation
Konrad has approved Tugrul’s resignation
Preparing the surprise party for Tugrul
Manager Konrad received the announcement Guys Tugrul is resigning his position, and you Konrad are invited to his surprise party
Employee Altan received the announcement Guys Tugrul is resigning his position, and you Altan are invited to his surprise party
Employee Oguz received the announcement Guys Tugrul is resigning his position, and you Oguz are invited to his surprise party

In Contemporary Examples

  • java.util.Timer class schedule methods,
  • Java Executor executor method,
  • java.lang.reflect.Method invoke method,
  • JMS and Message Brokers heavily utilizes this pattern along with the Observer Pattern,
  • Spring’s MVC Pattern makes use in the Dispatcher Servlet where mediator handles all the web requests as well as the controller objects.