Design Patterns in Action(4)- Adapter

A series of programming design patterns illustration with examples with JavaScript/Python

Creational Pattern — Adapter

Simply put, the Adapter pattern allows two incompatible piece to work together. This is done by creating an adapter to convert one of the pieces’ interface to be acceptable by another.

  • Client : calls the Adapter to talk to Adaptee
  • Adapter : twist the Adaptee’s interface to make it acceptable by the Client
  • Adaptee : does nothing, simply has its interface to be twisted by Adapter.

This allows for loose coupling as the two otherwise incompatible pieces can separate from each other, and it’s down to the adapter to create the communication channel. Most likely, you have been using adapter already, like when you integrate a 3rd party API into the existing infrastructure.

Note that to keep the adapter light and easy to maintain, you should only put connection logic in it but not business logic.

Let’s look at a python implementation first:

import abc


class BreadAdapterInterface(metaclass=abc.ABCMeta):
def __init__(self):
pass

@abc.abstractmethod
def labelBread(self, **args):
pass

@abc.abstractmethod
def chooseFlour(self, **args):
pass

@abc.abstractmethod
def waitForBake(self, **args):
pass


class BreadAdaptee():
def __init__(self, kind=None, flour_kind="white",
rise_in_min=0, bake_in_min=0, temp=200):
self.kind = kind
self.flour_kind = flour_kind
self.rise_in_min = rise_in_min
self.bake_in_min = bake_in_min
self.temp = temp

def label_bread(self, kind):
self.kind = kind

def choose_flour(self, flour_kind):
self.flour_kind = flour_kind

def wait_for_bake(self, bake_in_min, temp):
self.bake_in_min = bake_in_min
self.temp = temp


class BreadAdapter(BreadAdapterInterface):
__bread = None

def __init__(self, bread=BreadAdaptee()):
self.__bread = bread

def labelBread(self, **args):
return self.__bread.label_bread(args)

def chooseFlour(self, **args):
return self.__bread.choose_flour(args)

def waitForBake(self, **args):
return self.__bread.wait_for_bake(args)


breadAdapter = BreadAdapter()
breadAdapter.chooseFlour("Wholemeal")

Now another one for JavaScript:

class BreadAdaptee {
constructor(
kind = None,
flour_kind = "white",
rise_in_min = 0,
bake_in_min = 0,
temp = 200
) {
this.kind = kind;
this.flour_kind = flour_kind;
this.rise_in_min = rise_in_min;
this.bake_in_min = bake_in_min;
this.temp = temp;
}

label_bread(kind) {
this.kind = kind;
}

choose_flour(flour_kind) {
this.flour_kind = flour_kind;
}

wait_for_bake(bake_in_min, temp) {
this.bake_in_min = bake_in_min;
this.temp = temp;
}
}
class BreadAdapter {
constructor() {
this.bread = new BreadAdaptee();
}
operation(operation, ...args) {
switch (operation) {
case "labelBread":
return this.bread.label_bread(args);
case "chooseFlour":
return this.bread.choose_flour(args);
case "waitForBake":
return this.bread.wait_for_bake(args);
default:
return undefined;
}
}
}

//Client call:

const breadAdapter = new BreadAdapter();
breadAdapter.operation("chooseFlour", "wholemeal");

That’s so much of it! Happy Reading!

Hi :)