Definition
The Adapter design pattern is useful when you have different or incompatible interfaces and you need the client to be able to use both in the same way.
The Adapter pattern says in its definition that it converts an interface or class to another interface that the client expects.
How the client uses the adapter?
1. The client makes a request to the adapter by calling a method on it using the target interface.
2. The adapter translates the request into one or more calls on the adaptee using the adaptee interface.
3. The client receives the results of the call and never knows there is an adapter doing the translation.
Source: Head First Design Patterns
Implementation
Let's say that we have a system that works with different types of engines (economical and common) that share characteristics and functionality. If you want to add to the system a class of type Electric Engine with different characteristics from the others, you must adapt the new class without affecting the initial logic of the application.
Since we are going to add a new engine that has a different behavior from the rest we can use the Adapter pattern.
As we see in the diagram we use inheritance to share common functionalities for the different types of engines, however, we show that not all of them behave in the same way as the case of Electric Engine, For this reason, we cannot inherit directly from the Engine class, since the methods that it provides us would not be useful for this class.
In that case, we can use an Adapter class that would serve as a bridge between the parent class and the class that must be adapted, so this adapter would be in charge of establishing communication with the Electric Engine and executing the requests that the client makes.
TDD
Let's start creating some test cases. First, we need to add a test and see if any new test fails, then we update the code to make the test pass, and last we run the code again. In this case, we created a test for the turnOn and turnOff method.
@Test
public void economicalEngineisOntest(){
Engine engine = new EconomicalEngine();
engine.turnOn();
boolean isOn = engine.isOn();
assertEquals(true, isOn);
}
@Test
public void economicalEngineisOfftest(){
Engine engine = new EconomicalEngine();
engine.turnOff();
boolean isOn = engine.isOn();
assertEquals(false, isOn);
}
@Test
public void commonEngineisOntest(){
Engine engine = new CommonEngine();
engine.turnOn();
boolean isOn = engine.isOn();
assertEquals(true, isOn);
}
@Test
public void commonEngineisOfftest(){
Engine engine = new CommonEngine();
engine.turnOff();
boolean isOn = engine.isOn();
assertEquals(false, isOn);
}
@Test
public void electricalEngineisOntest(){
Engine engine = new ElectricalEngineAdapter();
engine.turnOn();
boolean isOn = engine.isOn();
assertEquals(true, isOn);
}
@Test
public void electricalEngineisOfftest(){
Engine engine = new ElectricalEngineAdapter();
engine.turnOff();
boolean isOn = engine.isOn();
assertEquals(false, isOn);
}
Engine Class
This class is from which the different types of motors will inherit, it provides the common methods (turn on, isOn, turn off) for their operation.
public abstract class Engine {
abstract public void turnOn();
abstract public boolean isOn();
abstract public void turnOff();
}
Common and Economical Engine Class
This class represents the structure of the normal motors with which the system works, basically, they inherit from the Motor class and perform the basic operation that it provides.
public class CommonEngine extends Engine{
boolean isOn;
public CommonEngine() {
super();
System.out.println("Creating a common engine");
}
@Override
public void turnOn() {
this.isOn = true;
}
@Override
public boolean isOn() {
return this.isOn;
}
@Override
public void turnOff() {
this.isOn = false;
}
}
public class EconomicalEngine extends Engine{
boolean isOn;
public EconomicalEngine() {
super();
System.out.println("Creating an economical engine");
}
@Override
public void turnOn() {
this.isOn = true;
}
@Override
public void turnOff() {
this.isOn = false;
}
@Override
public boolean isOn() {
return this.isOn;
}
}
Electrical Engine Adapter Class
This class is the bridge In which the incompatible class can be used, inherits from the Engine class, and can communicate with the class to be adapted using an instance of it.
public class ElectricalEngineAdapter extends Engine{
private ElectricalEngine electricalEngine;
public ElectricalEngineAdapter() {
super();
this.electricalEngine = new ElectricalEngine();
System.out.println("Creating electrical engine adapter");
}
@Override
public void turnOn() {
this.electricalEngine.plugIn();
}
@Override
public void turnOff() {
this.electricalEngine.unplug();
}
@Override
public boolean isOn() {
return electricalEngine.isPlugged();
}
}
Electrical Engine Class
This is the class we need to adapt, as we see it has different characteristics from the other types of engines in the system, therefore it cannot inherit directly from the Engine class.
public class ElectricalEngine {
private boolean plugged;
public ElectricalEngine() {
this.plugged = false;
System.out.println("Creating electrical engine");
}
public void plugIn() {
this.plugged = true;
}
public boolean isPlugged(){
return this.plugged;
}
public void unplug(){
this.plugged = false;
}
}
Reference
Head First Design Patterns
by Eric Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra
Released October 2004
Publisher(s): O'Reilly Media, Inc.
Comments
Post a Comment