The adapter design pattern is a structural pattern which allows two interfaces which wouldn’t be able to work together actually work together. It does this by wrapping the “adaptee” with a class that is supported by the main interface.

Let’s take a look at a coded example, which uses video game enemies as the objects.
First we have our main interface of EnemyAttacker.
public interface EnemyAttacker {
public void FireWeapon();
public void driveForward();
public void assignDriver(String driverName);
}
Next we have a class representing an EnemyTank which implements the EnemyAttacker interface.
import java.util.Random;
public class EnemyTank implements EnemyAttacker {
Random generator = new Random();
@Override
public void FireWeapon() {
int attackDamage = generator.nextInt(10) + 1;
System.out.println("Enemy Tank Does" + attackDamage + " Damage");
}
@Override
public void driveForward() {
int movement = generator.nextInt(5) +1;
System.out.println("Enemy Tank moves " + movement + " spaces.");
}
@Override
public void assignDriver(String driverName) {
System.out.println(driverName + " is driving the tank");
}
}
Everything checks out, the EnemyTank inherits and defines fully the methods from the interface. But what if we have an Enemy object that doesn’t have a driver? Or a weapon to fire? Or what if it doesn’t even drive forward? Well that’s exactly what we want to implement next; an EnemyRobot. Clearly it doesn’t inherit the same kind of methods that EnemyTank should. What can we do? We create an adapter class which helps the interface for EnemyRobot and EnemyTank work together, like so!
public class EnemyRobotAdapter implements EnemyAttacker {
EnemyRobot theRobot;
public EnemyRobotAdapter(EnemyRobot newRobot) {
theRobot = newRobot;
}
@Override
public void FireWeapon() {
theRobot.smashWithHands();
}
@Override
public void driveForward() {
theRobot.walkForward();
}
@Override
public void assignDriver(String driverName) {
theRobot.reactToHuman(driverName);
}
}
Here we are able to override the non-compatible methods from EnemyAttacker and implement our own methods that apply to the RobotAttacker, defined in the following class of EnemyRobot; the Adaptee.
import java.util.Random;
public class EnemyRobot {
Random generator = new Random();
public void smashWithHands() {
int attackDamage = generator.nextInt(10)+1;
System.out.println("Enemy Robot Causes " + attackDamage + " With Its Hands.");
}
public void walkForward() {
int movement = generator.nextInt(5) +1;
System.out.println("Enemy Robot Walks Forward " + movement + " Spaces.");
}
public void reactToHuman(String driverName) {
System.out.println("Enemy Robot Tramps on " + driverName);
}
}
Finally, we have our main class. In our main method, we create both a EnemyTank and an EnemyRobot, which both use the same methods that were implemented from EnemyAttacker.
public class TestEnemyAttackers {
public static void main(String[] args) {
EnemyTank rx7Tank = new EnemyTank();
EnemyRobot fredTheRobot = new EnemyRobot();
EnemyAttacker robotAdapter = new EnemyRobotAdapter(fredTheRobot);
System.out.println("The Robot");
fredTheRobot.reactToHuman("Paul");
fredTheRobot.walkForward();
fredTheRobot.smashWithHands();
System.out.println("The Enemy Tank");
rx7Tank.assignDriver("Frank");
rx7Tank.driveForward();
rx7Tank.FireWeapon();
System.out.println("The Robot with Adapter");
robotAdapter.assignDriver("Mark");
robotAdapter.driveForward();
robotAdapter.FireWeapon();
}
}
To see the full project code, visit this project on my GitHub here!