Implementation

Let’s say, in the Flutter application we want to collect our contacts from two different sources. Unfortunately, these two sources provide the contacts in two different formats — JSON and XML. Also, we want to create a Flutter widget which represents this information in a list. However, to make the widget universal, it cannot be tied to a specific data format (JSON or XML), so it accepts these contacts as a list of Contact objects and does not know anything about how to parse JSON or XML strings to the required data structure. So we have two incompatible interfaces — our UI component (widget), which expects a list of Contact objects, and two APIs, which return contacts’ information in two different formats. As you could have guessed, we will use the Adapter design pattern to solve this problem.

Class diagram

The class diagram below shows the implementation of the Adapter design pattern using the object adapter method.

Class Diagram — Implementation of the Adapter design pattern

First of all, there are two APIs: JsonContactsApi and XmlContactsApi. These two APIs have different methods to return contacts information in two different formats — JSON and XML. Hence, two different adapters should be created to convert the specific contacts’ representation to the required format which is needed in the ContactsSection component (widget) — list of Contact objects. To unify the contract (interface) of adapters, IContactsAdapter abstract class is created which requires implementing (override) the getContacts() method in all the implementations of this abstract class. JsonContactsAdapter implements the IContactsAdapter, uses the JsonContactsApi to retrieve contacts information as a JSON string, then parses it to a list of Contact objects and returns it via getContacts() method. Accordingly, XmlContactsAdapter is implemented in the same manner, but it receives the data from XmlContactsApi in XML format.

Contact

Contact is a plain Dart class (as some people from Java background would call it — POJO) to store the contact’s information.

This class is used inside the UI widget ContactsSection and both of the adapters to return the parsed data from APIs in an acceptable format for the UI.

JsonContactsApi

A fake API which returns contacts’ information as a JSON string.

XmlContactsApi

A fake API which returns contacts’ information as an XML string.

IContactsAdapter

A contract (interface) which unifies adapters and requires them to implement the method getContacts().

Dart language does not support the interface as a class type, so we define an interface by creating an abstract class and providing a method header (name, return type, parameters) without the default implementation.

JsonContactsAdapter

An adapter, which implements the getContacts() method. Inside the method, contacts’ information is retrieved from JsonContactsApi as a JSON string and parsed to the required return type (a list of Contact objects).

XmlContactsAdapter

An adapter, which implements the getContacts() method. Inside the method, contacts’ information is retrieved from XmlContactsApi as an XML string and parsed to the required return type (a list of Contact objects).

Example

First of all, a markdown file is prepared and provided as a pattern’s description:

The example itself uses ContactsSection component which requires a specific adapter of type IContactsAdapter to be injected via constructor.

ContactsSection widget uses the injected adapter of type IContactsAdapter. The widget only cares about the adapter’s type (interface), but not its specific implementation. Hence, we can provide different adapters of type IContactsAdapter which load the contacts’ information from different data sources without making any changes to the UI.

The final result of the Adapter’s implementation looks like this:

All of the code changes for the Adapter design pattern and its example implementation could be found here.