Adapter pattern
The adapter converts one interface to another that the client expects. It is also also known as wrapper.
problems
Suppose we have some logic that work with objects through interface. For example, a Scene class and a Shape interface. And now we need add objects to the scene, that implement own interface GeometricShape. What we can do?
We can try change source of Scene for supporting GeometricShape. But this will complicate the Scene class. And if Scene is already well tested, then it's better not to change it at all. And finally, Scene with Shape may belong to external library, that we can not change.
We can try change code of GeometricShape. But again, GeometricShape may belong to external library, that we can not change. Even if it is possible, there may be a bunch of dependencies that also need to be fixed.
To solve such problems the adapter design pattern is used.
advantages
- Allows you to use incompatible objects in one way.
- Reuses existing code.
adapter vs bridge vs proxy vs decorator
Technically, the adapter can be look like other patterns, but
- adapter is used for existing code, bridge is used before the application components are designed
- proxy provides same interface, adapter provides a different interface
- decorator add new functionality or modify existing, but the adapter does not
example
// first interface
interface Shape {
void draw();
}
// second interface
interface GeometricShape {
void drawShape();
}
// client, that expects Shape interface
public class Scene {
public void addShape(Shape shape) {/* ... */}
public void drawScene() { /* ... */ }
}
// Adapter, that converts a GeometricShape interface
// to the Shape interface
public class GeometricShapeAdapter implements Shape {
private GeometricShape shape;
GeometricShapeAdapter(GeometricShape shape) {
this.shape = shape;
}
@Override
public void draw() {
shape.drawShape();
}
}