Adapter
Adapter
Adapter es un patrón de diseño estructural que permite la colaboración entre objetos con interfaces incompatibles.
Problema
Imaginemos que tenemos un sistema de medición de la temperatura en grados celsius, pero necesitamos incorporar una librería externa que mida la temperatura en grados fahrenheit y que nos la devuelva en grados celsius. Pero necesitamos adaptar esta librería para que devuelva la temperatura en celsius que es lo que nuestro sistema desea utilizar..
Imaginemos que tenemos lo siguiente:
/**
* Interfaz objetivo
*/
public interface MetricTemperatureSystem {
double getTemperature();
void setTemperature(double temperature);
}
Esta es la interfaz target, en el patrón adapter, la interfaz target es aquella a la que nos queremos adaptar, es decir la que estamos usando en este momento.
Por otro lado podemos ir teniendo implementaciones de esta interfaz, ejemplo:
public class Celsius implements MetricTemperatureSystem {
private double temperature;
public Celsius() {
}
public Celsius(double temperature) {
this.temperature = temperature;
}
@Override
public double getTemperature() {
return temperature;
}
@Override
public void setTemperature(double temperature) {
this.temperature = temperature;
}
@Override
public String toString() {
return String.format("%s° C", temperature);
}
}
Ahora bien, imaginemos que usamos una librería de terceros que dispone de la siguiente interfaz y de la siguiente clase:
public interface ImperialTemperatureSystem {
double getTemperature();
void setTemperature(double temperature);
}
Las interfaces son las mismas, pero una clase devuelve la temperatura en Fahrenheit y la otra en celsius(hipotéticamente dado que en el código no esta presente)
/**
* Objeto incompatible
*/
public class Fahrenheit implements ImperialTemperatureSystem {
private double temperature;
public Fahrenheit() {
}
public Fahrenheit(double temperature) {
this.temperature = temperature;
}
@Override
public double getTemperature() {
return temperature;
}
@Override
public void setTemperature(double temperature) {
this.temperature = temperature;
}
@Override
public String toString() {
return String.format("%s° F", temperature);
}
}
Ahora bien si queremos que esta clase implemente nuestra interfaz target y que pase la temperatura de fahrenheit a celsius podemos crear una clase adapter.
/**
* Clase adaptadora que envuelve al objeto incompatible
*/
public class CelsiusAdapter implements MetricTemperatureSystem {
private static final double BASE_SCALE = 32.;
private static final double FACTOR_TO_FAHRENHEIT = 9. / 5.;
private static final double FACTOR_TO_CELSIUS = 5. / 9.;
private Fahrenheit fahrenheit;
public CelsiusAdapter(Fahrenheit fahrenheit) {
this.fahrenheit = fahrenheit;
}
@Override
public double getTemperature() {
return (fahrenheit.getTemperature() - BASE_SCALE) * FACTOR_TO_CELSIUS;
}
@Override
public void setTemperature(double temperature) {
fahrenheit.setTemperature(temperature * FACTOR_TO_FAHRENHEIT + BASE_SCALE);
}
@Override
public String toString() {
return String.format("%s° C", getTemperature());
}
}
Esta es una clase que recibe una instancia de la clase incompatible e implementa la interfaz target.
Por lo que usamos el objeto y hacemos los cambios correspondientes para que devuelva lo mismo que nuestras implementaciones.
public static void main(String[] args) {
Fahrenheit fahrenheit = new Fahrenheit(98.6);
List<MetricTemperatureSystem> temperatureList = Arrays.asList(
new Celsius(37),
new CelsiusAdapter(fahrenheit)
);
System.out.println(fahrenheit);
System.out.println(temperatureList);
}
Aquí podemos ver que el primer objeto la temperatura que marca es 98.6 fahrenheit pero usando esa mista temperatura en nuestro adapter, la convertira a grados celsius.
98.6° F
[37.0° C, 37.0° C]