Buscar..


Patrón Adaptador (PHP)

Un ejemplo del mundo real que utiliza un experimento científico en el que se realizan ciertas rutinas en diferentes tipos de tejido. La clase contiene dos funciones por defecto para obtener el tejido o la rutina por separado. En una versión posterior, lo adaptamos utilizando una nueva clase para agregar una función que obtiene ambas. Esto significa que no hemos editado el código original y, por lo tanto, no corremos ningún riesgo de romper nuestra clase existente (y no volver a realizar la prueba).

class Experiment {
    private $routine;
    private $tissue;
    function __construct($routine_in, $tissue_in) {
        $this->routine = $routine_in;
        $this->tissue  = $tissue_in;
    }
    function getRoutine() {
        return $this->routine;
    }
    function getTissue() {
        return $this->tissue;
    }
}

class ExperimentAdapter {
    private $experiment;
    function __construct(Experiment $experiment_in) {
        $this->experiment = $experiment_in;
    }
    function getRoutineAndTissue() {
        return $this->experiment->getTissue().' ('. $this->experiment->getRoutine().')';
    }
}

Adaptador (Java)

Supongamos que en su base de código actual, existe MyLogger interfaz de MyLogger así:

interface MyLogger {
    void logMessage(String message);
    void logException(Throwable exception);
}

Digamos que ha creado algunas implementaciones concretas de estos, como MyFileLogger y MyConsoleLogger .

Ha decidido que desea usar un marco para controlar la conectividad Bluetooth de su aplicación. Este marco contiene un BluetoothManager con el siguiente constructor:

class BluetoothManager {
    private FrameworkLogger logger;

    public BluetoothManager(FrameworkLogger logger) {
        this.logger = logger;
    }
}

El BluetoothManager también acepta un registrador, ¡lo cual es genial! Sin embargo, espera un registrador cuya interfaz fue definida por el marco y han usado la sobrecarga de métodos en lugar de nombrar sus funciones de manera diferente:

interface FrameworkLogger {
    void log(String message);
    void log(Throwable exception);
}

Ya tiene un montón de implementaciones de MyLogger que le gustaría reutilizar, pero no se ajustan a la interfaz de FrameworkLogger . Aquí es donde entra el patrón de diseño del adaptador:

class FrameworkLoggerAdapter implements FrameworkLogger {
    private MyLogger logger;

    public FrameworkLoggerAdapter(MyLogger logger) {
        this.logger = logger;
    }

    @Override
    public void log(String message) {
        this.logger.logMessage(message);
    }

    @Override
    public void log(Throwable exception) {
        this.logger.logException(exception);
    }
}

Al definir una clase de adaptador que implementa la interfaz de FrameworkLogger y acepta una implementación de MyLogger , la funcionalidad se puede asignar entre las diferentes interfaces. Ahora es posible usar el MyLogger BluetoothManager con todas las implementaciones de MyLogger como:

FrameworkLogger fileLogger = new FrameworkLoggerAdapter(new MyFileLogger());
BluetoothManager manager = new BluetoothManager(fileLogger);

FrameworkLogger consoleLogger = new FrameworkLoggerAdapter(new MyConsoleLogger());
BluetoothManager manager2 = new BluetoothManager(consoleLogger);

Ejemplo de Java

Un gran ejemplo existente del patrón del adaptador se puede encontrar en las clases SWT MouseListener y MouseAdapter .

La interfaz de MouseListener tiene el siguiente aspecto:

public interface MouseListener extends SWTEventListener {
    public void mouseDoubleClick(MouseEvent e);
    public void mouseDown(MouseEvent e);
    public void mouseUp(MouseEvent e);
}

Ahora imagine un escenario en el que está creando una UI y agregando estos oyentes, pero la mayoría de las veces no le importa nada más que cuando se hace clic en algo (mouseUp). No querrías estar constantemente creando implementaciones vacías:

obj.addMouseListener(new MouseListener() {

    @Override
    public void mouseDoubleClick(MouseEvent e) {
    }

    @Override
    public void mouseDown(MouseEvent e) {
    }

    @Override
    public void mouseUp(MouseEvent e) {
        // Do the things
    }

});

En su lugar, podemos usar MouseAdapter:

public abstract class MouseAdapter implements MouseListener {
    public void mouseDoubleClick(MouseEvent e) { }
    public void mouseDown(MouseEvent e) { }
    public void mouseUp(MouseEvent e) { }
}

Al proporcionar implementaciones vacías y predeterminadas, somos libres de anular solo aquellos métodos que nos interesan en el adaptador. Siguiendo el ejemplo anterior:

obj.addMouseListener(new MouseAdapter() {

    @Override
    public void mouseUp(MouseEvent e) {
        // Do the things
    }

});

Adaptador (UML y ejemplo de situación)

Para hacer un uso del patrón de adaptador y el tipo de situación en la que se puede aplicar más imaginable, aquí se ofrece un ejemplo pequeño, simple y muy concreto. No habrá ningún código aquí, solo UML y una descripción de la situación de ejemplo y su problema. Es cierto que el contenido UML está escrito como Java. (Bueno, el texto de la sugerencia decía "Los buenos ejemplos son principalmente código", creo que los patrones de diseño son lo suficientemente abstractos como para ser presentados de una manera diferente, también).

En general, el patrón de adaptador es una solución adecuada para una situación en la que tiene interfaces incompatibles y ninguna de ellas puede reescribirse directamente.

Imagina que tienes un buen servicio de reparto de pizzas. Los clientes pueden realizar pedidos en línea en su sitio web y usted tiene un sistema pequeño que utiliza una Pizza clase para representar sus pizzas y calcular facturas, informes de impuestos y más. El precio de sus pizzas se da como un solo entero que representa el precio en centavos (de la moneda de su elección).

introduzca la descripción de la imagen aquí

Su servicio de entrega está funcionando muy bien, pero en algún momento ya no puede manejar el creciente número de clientes por su cuenta, pero aún desea expandirse. Decide agregar sus pizzas al menú de un gran servicio de entrega meta en línea. Ofrecen muchas comidas diferentes, no solo pizzas, por lo que su sistema hace un mayor uso de la abstracción y tiene una Interfaz IMeal representa las comidas junto con una clase de MoneyAmount representa el dinero.

introduzca la descripción de la imagen aquí

MoneyAmount consta de dos enteros como entrada, uno para la cantidad (o alguna moneda aleatoria) antes de la coma, y ​​otro para la cantidad de centavos de 0 a 99 después de la coma;

introduzca la descripción de la imagen aquí

Debido al hecho de que el precio de su Pizza es un solo entero que representa el precio total como una cantidad de centavo (> 99), no es compatible con IMeal . Este es el punto en el que el patrón del adaptador entra en juego: en caso de que requiera demasiado esfuerzo cambiar su propio sistema o crear uno nuevo y tenga que implementar una interfaz incompatible, es posible que desee aplicar el patrón del adaptador.

Hay dos formas de aplicar el patrón: adaptador de clase y adaptador de objeto.

Ambos tienen en común que un adaptador ( PizzaAdapter ) funciona como algún tipo de traductor entre la nueva interfaz y el adaptee ( Pizza en este ejemplo). El adaptador implementa la nueva interfaz ( IMeal ) y luego hereda de Pizza y convierte su propio precio de un entero a dos (adaptador de clase)

introduzca la descripción de la imagen aquí

o tiene un objeto de tipo Pizza como atributo y convierte los valores de ese (adaptador de objeto).

introduzca la descripción de la imagen aquí

Al aplicar el patrón de adaptador, usted podrá "traducir" entre interfaces incompatibles.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow