Ricerca…


Adapter Pattern (PHP)

Un esempio del mondo reale che utilizza un esperimento scientifico in cui determinate routine vengono eseguite su diversi tipi di tessuto. La classe contiene di default due funzioni per ottenere separatamente il tessuto o la routine. In una versione successiva l'abbiamo quindi adattato utilizzando una nuova classe per aggiungere una funzione che ottiene entrambi. Ciò significa che non abbiamo modificato il codice originale e quindi non corriamo alcun rischio di rompere la nostra classe esistente (e nessuna ripetizione).

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().')';
    }
}

Adattatore (Java)

Supponiamo che nella tua base di codice attuale esista MyLogger interfaccia MyLogger modo:

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

Diciamo che hai creato alcune implementazioni concrete di questi, come MyFileLogger e MyConsoleLogger .

Hai deciso di voler utilizzare un framework per il controllo della connettività Bluetooth della tua applicazione. Questo framework contiene un BluetoothManager con il seguente costruttore:

class BluetoothManager {
    private FrameworkLogger logger;

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

Il BluetoothManager accetta anche un logger, che è fantastico! Tuttavia, si aspetta un logger di cui l'interfaccia è stata definita dal framework e che hanno usato l'overloading del metodo invece di nominare le loro funzioni in modo diverso:

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

Hai già un sacco di implementazioni MyLogger che vorresti riutilizzare, ma non si adattano all'interfaccia di FrameworkLogger . È qui che entra in gioco il modello di design dell'adattatore:

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);
    }
}

Definendo una classe adattatore che implementa l'interfaccia FrameworkLogger e accetta un'implementazione MyLogger la funzionalità può essere mappata tra le diverse interfacce. Ora è possibile utilizzare BluetoothManager con tutte le implementazioni di MyLogger modo:

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

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

Esempio di Java

Un grande esempio esistente del pattern Adapter possono essere trovate nelle SWT MouseListener e MouseAdapter classi.

L'interfaccia MouseListener ha il seguente aspetto:

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

Ora immagina uno scenario in cui stai costruendo un'interfaccia utente e aggiungendo questi listener, ma la maggior parte delle volte non ti interessa nulla se non quando qualcosa viene cliccato (mouseUp). Non vorrai creare costantemente implementazioni vuote:

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
    }

});

Invece, possiamo usare MouseAdapter:

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

Fornendo implementazioni predefinite vuote, siamo liberi di ignorare solo i metodi che ci interessano dall'adattatore. Seguendo l'esempio precedente:

obj.addMouseListener(new MouseAdapter() {

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

});

Adattatore (UML e situazione di esempio)

Per rendere l'uso del modello di adattatore e il tipo di situazione in cui può essere applicato più immaginabile, qui viene fornito un esempio piccolo, semplice e molto concreto. Non ci sarà codice qui, solo UML e una descrizione della situazione di esempio e il suo problema. A dire il vero, il contenuto UML è scritto come Java. (Bene, il testo suggerito diceva "I buoni esempi sono per lo più codice", penso che i modelli di design siano abbastanza astratti da poter essere introdotti in un modo diverso).

In generale, il modello dell'adattatore è una soluzione adeguata per una situazione in cui si hanno interfacce incompatibili e nessuna di esse può essere riscritta direttamente.

Immagina di gestire un piccolo servizio di consegna della pizza. I clienti possono ordinare online sul tuo sito web e hai un piccolo sistema che utilizza una Pizza classe per rappresentare le tue pizze e calcolare le bollette, i rapporti fiscali e altro. Il prezzo delle tue pizze viene indicato come un singolo intero che rappresenta il prezzo in centesimi (della valuta di tua scelta).

inserisci la descrizione dell'immagine qui

Il tuo servizio di consegna sta funzionando alla grande, ma a un certo punto non puoi più gestire il crescente numero di clienti da solo ma desideri comunque espanderlo. Decidi di aggiungere le tue pizze al menu di un grande servizio di consegna meta online. Offrono molti pasti diversi, non solo le pizze, quindi il loro sistema fa un uso più IMeal dell'astrazione e ha un IMeal interfaccia IMeal rappresenta i pasti accompagnati da una classe MoneyAmount rappresenta denaro.

inserisci la descrizione dell'immagine qui

MoneyAmount consiste di due interi come input, uno per l'importo (o una valuta casuale) prima della virgola e uno per l'importo centesimo da 0 a 99 dopo la virgola;

inserisci la descrizione dell'immagine qui

A causa del fatto che il prezzo della tua Pizza è un numero intero singolo che rappresenta il prezzo totale come una quantità di centesimo (> 99), non è compatibile con IMeal . Questo è il punto in cui entra in gioco il modello di adattatore: nel caso in cui ci vorrebbe troppo tempo per modificare il proprio sistema o crearne uno nuovo e si deve implementare un'interfaccia incompatibile, si consiglia di applicare il patttern dell'adattatore.

Esistono due modi per applicare il modello: adattatore di classe e adattatore di oggetti.

Entrambi hanno in comune che un adattatore ( PizzaAdapter ) funziona come una sorta di traduttore tra la nuova interfaccia e l'adaptee ( Pizza in questo esempio). L'adattatore implementa la nuova interfaccia ( IMeal ) e quindi eredita da Pizza e converte il proprio prezzo da un numero intero a due (adattatore classe)

inserisci la descrizione dell'immagine qui

o ha un oggetto di tipo Pizza come attributo e converte i valori di quello (oggetto adattatore).

inserisci la descrizione dell'immagine qui

Applicando il modello dell'adattatore, sarà possibile "tradurre" tra interfacce incompatibili.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow