To make the use of the adapter pattern and the kind of situation when it may be applied more imaginable, a small, simple and very concrete example is given here. There will be no code in here, just UML and a description of the example situation and its problem. Admittedly, the UML content is written like Java. (Well, the hint text said "Good examples are mostly code", I think design patterns are abstract enough to be introduced in a different way, too.)
In general, the adapter pattern is an adequate solution for a situation when you have incompatible interfaces and none of them can be directly rewritten.
Imagine you're running a nice little pizza delivery service. Customers can order online on your website and you have small system using a class Pizza
to represent your pizzas and calculate bills, tax reports and more.
The price of your pizzas is given as a single integer representing the price in cent (of the currency of your choice).
Your delivery service is working out great, but at some point you cannot handle the growing number of customers on your own anymore but you still want to expand.
You decide to add your pizzas to the menu of a big online meta delivery service.
They offer a lot of different meals — not only pizzas — so their system makes more use of abstraction and has an Interface IMeal
representing meals coming along with a class MoneyAmount
representing money.
MoneyAmount
consists of two integers as input, one for the amount (or some random currency) before the comma, and one for the cent amount from 0 to 99 after the comma;
Due to the fact that the price of your Pizza
is a single integer representing the total price as an amount of cent (> 99), it is not compatible with IMeal
.
This is the point where the adapter pattern comes into play: In case it would take too much effort to change your own system or create a new one and you have to implement an incompatible interface, you may want to apply the adapter patttern.
There are two ways of applying the pattern: class adapter and object adapter.
Both have in common that an adapter (PizzaAdapter
) works as some kind of translator between the new interface and the adaptee (Pizza
in this example).
The adapter implements the new interface (IMeal
) and then either inherits from Pizza
and converts its own price from one integer to two (class adapter)
or has an object of type Pizza
as an attribute and converts the values of that (object adapter).
By applying the adapter pattern, you will kind of "translate" between incompatible interfaces.