2 - Adapter
Tags: flutter, dart, oop, programming
Published: 2021-01-25 10:20:53

In the last article, I have analysed the first design pattern in the series — Singleton, provided some general thoughts about its structure, applicability, pros and cons, implemented it in several different ways. This time, I would like to analyse and implement a design pattern which belongs to the category of structural design patterns — Adapter.

## Table of Contents

* What is the Adapter design pattern?
* Analysis
* Implementation
* Your Contribution

## What is the Adapter design pattern?

![Incompatible Simpsons](https://dev-to-uploads.s3.amazonaws.com/i/k1r7kziwf9821lc7tb5n.gif)

**Adapter** is a **structural** design pattern, also known as **wrapper**. It is one of the most common and most useful design patterns available to us as software developers. The intention of this design pattern is described in the [GoF book](https://en.wikipedia.org/wiki/Design_Patterns):

> Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

Let’s say you want to use some kind of a third-party library which has the functionality you need. Also, you have a class that needs to utilize a particular interface, but interfaces between your code and the library are incompatible. In this case, you can use the library’s code by creating an adapter class that “sits” between your code and the code you want to use from that library. Moreover, the pattern is useful when you want to ensure that some particular piece of code in your software could be reused by wrapping it with an adapter and exposing an interface to it. This lets the future implementations in your code to depend on Adapter interfaces, rather than concrete classes directly. Sounds good already? Well, let’s move to the analysis to understand how this pattern works and how it could be implemented.

## Analysis

The class diagram below shows the general structure of the Adapter design pattern.

![Adapter Class Diagram](https://dev-to-uploads.s3.amazonaws.com/i/4c0ucrznu6ia21wlvtew.png)

To be more specific, there are two general implementations of Adapter with a different structure — **Object** and **Class** adapters (we will talk about the differences between these two next). Despite different structure between object and class adapters, they share the same idea of participants (elements or classes used to implement the pattern):

* *Target* or *ITarget* defines the domain-specific interface that *Client* uses;
* *Client* collaborates with objects conforming to the *Target* interface;
* *Adaptee* defines an existing interface that needs adapting (e.g. third-party library);
* *Adapter* adapts the interface of *Adaptee* to the *Target* interface. This is the main node in the pattern, which connects the *Client* code with the code which wants to be used (*Adaptee*).

### Object adapter vs Class adapter

![Object vs Class adapter](https://dev-to-uploads.s3.amazonaws.com/i/8wzo3dnny3hna5qrjeqk.gif)

To begin with, both object and class adapters are valid implementations of the Adapter design pattern, but their structure is different as well as their advantages and trade-offs. **Object adapter** relies on object composition to implement a Target interface in terms of (by delegating to) an *Adaptee* object. That is, adapter implements the *Target* operation by calling a concrete operation on the property or instance of *Adaptee* class. The **class adapter** uses inheritance to implement a *Target* interface in terms of (by inheriting from) an *Adaptee* class. This way, the concrete operation from the *Adaptee* class could be called directly from the implementation of *Target* operation. The question is, which one to use?

My personal choice between these two possible implementations is **object adapter**. Here are the reasons why:

1. In order to implement the Adapter design pattern using the class adapter method, the programming language of your choice must support multiple inheritance. In Dart, multiple inheritance is not supported.
2. One of the advantages of class adapter is that you can easily override the behaviour of the adaptee class — you extend the adaptee class, right? However, the object adapter method is more flexible since it commits to an Adaptee class at run-time (client and adaptee code are loosely-coupled). It means that you can create a single adapter which could use multiple different adaptees as long as their interfaces (types) matches the one adapter requires.
3. I prefer composition over inheritance. What I bear in my mind, if you try to reuse the code by inhering from a class, you make the subclass dependent on the parent class. When using composition, you decouple your code by providing interfaces which implementations can be easily replaced (in this case, the implementation of Adaptee could be replaced inside the Adapter class at run-time). This is only a glimpse of the Liskov substitution principle (the letter **L** in [SOLID](https://en.wikipedia.org/wiki/SOLID) principles), which is pretty difficult to understand and apply, but it is worth the effort.

### Applicability

The adapter design pattern could (and should!) be used when the interface of the third-party library (or any other code you want to use) does not match the one you are currently using in your application. This rule could also be applied when calling external data sources, APIs and you want to wrap and separate the data conversion code from the primary business logic in your program. The pattern is useful when you want to use multiple implementations (adaptees) that have similar functionality but use different APIs. In this case, all the “hard work” (implementation) could be done in the Adapter classes, whereas the domain-layer code will use the same interface of the adapters. Also, this code abstraction makes the unit testing of the domain-layer code a little bit easier.

## Implementation

![Let's Get Down To Business](https://dev-to-uploads.s3.amazonaws.com/i/sran2jb1782ulnvrtt94.gif)

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.

![Adapter Implementation Class Diagram](https://dev-to-uploads.s3.amazonaws.com/i/7afmexy9q3k8qja5jqc5.png)

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.

![contact.dart](https://dev-to-uploads.s3.amazonaws.com/i/vfjq0szs8jil5h6zrf96.png)

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.

![json_contacts_api.dart](https://dev-to-uploads.s3.amazonaws.com/i/i7j49ynabunskhfqucdc.png)

### XmlContactsApi

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

![xml_contacts_api.dart](https://dev-to-uploads.s3.amazonaws.com/i/exic29uxh923v2i7greo.png)

### IContactsAdapter

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

![icontacts_adapter.dart](https://dev-to-uploads.s3.amazonaws.com/i/t3x05t2lt8a5q4lsjncb.png)

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).

![json_contacts_adapter.dart](https://dev-to-uploads.s3.amazonaws.com/i/uveyx6b7ru5f8ngmuwr0.png)

### 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).

![xml_contacts_adapter.dart](https://dev-to-uploads.s3.amazonaws.com/i/dsutud8dabv81kdv16ob.png)

### Example

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

![Adapter Markdown](https://dev-to-uploads.s3.amazonaws.com/i/qsqu2c1wqus9mcnn6uda.gif)

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

![adapter_example.dart](https://dev-to-uploads.s3.amazonaws.com/i/04zqoko4ep53380qh2by.png)

*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.

![contacts_section.dart](https://dev-to-uploads.s3.amazonaws.com/i/55npvu3lkcimcrgs5he2.png)

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

![Adapter Example](https://dev-to-uploads.s3.amazonaws.com/i/pi9kvo64f62syinr39i3.gif)

All of the code changes for the Adapter design pattern and its example implementation could be found [here](https://github.com/mkobuolys/flutter-design-patterns/pull/3).

## Your Contribution

💖 or 🦄 this article to show your support and motivate me to write better!
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.
📢 Share this article with your friends, colleagues in social media.
➕ Follow me on dev.to or any other social media platform.
⭐ Star the [Github](https://github.com/mkobuolys/flutter-design-patterns) repository.