Design Patterns in Android — Adapter

Paulina Szklarska
3 min readOct 9, 2017

--

Design patterns are reusable solutions to the most commonly occurring software problems. They can speed up the development process by providing a proven way of resolving frequent issues.

In this series of articles I already wrote about:

Now it’s time for the Adapter!

Introduction

Adapter pattern is one of the structural patterns, which are used for class and object composition. This pattern is useful in situation when we have two different interfaces, we want to combine them and we can’t change them (unlike in the facade pattern). Thanks to this pattern we can build a bridge between them.

You can imagine Adapter pattern as the memory card adapter. We can have many of type cards (miniSD, microSD) and we’d like to read them all with a single card reader in the laptop. In this situation we can use adapter for memory card — a simple object that takes smaller card types and can be put into laptop as a one large card.

Adapter — example

Look at the example. Let’s assume we use library for Bluetooth in Android, which has its own implementation of Bluetooth Device — CoolBluetoothDevice (clever name, isn’t it?). On the other side we have a Android framework class — BluetoothDevice. They both are different and can’t be changed (it’s important). But we want to make them work together:

A — BluetoothDevice, B- CoolBluetoothDevice

As you can see, it’s not that easy to fit B (CoolBluetoothDevice) in A (a method which expects BluetoothDevice). That’s when Adapter pattern comes! Let’s look at the example:

Let’s assume we wrote common method for connecting using CoolBluetoothDevice objects, because that’s the object we’d like to use in the project instead of BluetoothDevice.

private void connect(final CoolBluetoothDevice bluetoothDevice) {
...
}

We’d like to call this method like this:

BluetoothDevice bluetoothDevice;
CoolBluetoothDevice coolBluetoothDevice;

public void connectDevices()
connect(coolBluetoothDevice);
connect(bluetoothDevice); // we can't do it
}

Unfortunately we can’t use this method with an old implementation which is BluetoothDevice. We need an adapter for it:

A — BluetoothDevice, B — CoolBluetoothDevice, C — BluetoothDeviceAdapter

We need to create an adapter class, which takes BluetoothDevice and makes it compatible as it’s CoolBluetoothDevice (in our case we’ll just create new CoolBluetoothDevice object with proper parameters and call connect() method)

class BluetoothDeviceAdapter {
private final BluetoothDevice bluetoothDevice;

public BluetoothDeviceAdapter(final BluetoothDevice
bluetoothDevice) {
this.bluetoothDevice = bluetoothDevice;
}

public void connect(final BluetoothDevice bluetoothDevice) {
CoolBluetoothDevice coolBluetoothDevice =
new CoolBluetoothDevice(
bluetoothDevice.getAddress(),
bluetoothDevice.getType(),
bluetoothDevice.getName(),
bluetoothDevice.getUuids());
connect(coolBluetoothDevice);
}

We created an adapter class which packs the old implementation (BluetoothDevice) and returns a new one(CoolBluetoothAdapter). This way we can use connect() method for both types:

BluetoothDevice bluetoothDevice;
CoolBluetoothDevice coolBluetoothDevice;

public void connectDevices()
connect(coolBluetoothDevice);
BluetoothDeviceAdapter bluetoothDeviceAdapter = new
BluetoothDeviceAdapter(bluetoothDevice);
bluetoothDeviceAdapter.connect(bluetoothDevice);
}

There are many other ways to extend this pattern, for example:

  • we can have common abstract implementation of both types (e.g. base class called Device) and handle bidirectional changes from BluetoothDevice to CoolBluetoothDevice and opposite — this way we don’t need to care which one type do we have now (helpful to remove instanceOf checks)
  • we can have adapter for more types — this way we’ll need extract connect() method to the interface

This pattern is very easy and useful when you try to extend existing implementation or combine it with the code from the library which can’t be modified. This pattern can be especially helpful in Android, where we have a framework that can’t be modified and other libraries with its own types.

That’s all! Stay tuned for more!

--

--

Paulina Szklarska
Paulina Szklarska

Written by Paulina Szklarska

Flutter GDE / Flutter & Android Developer / blogger / speaker / cat owner / travel enthusiast

Responses (1)