Class Adapter – Design Pattern Strutturale

Lo scopo del pattern Adapter è convertire l’interfaccia di una classe in un’altra interfaccia che i client si aspettano.

E’ definito anche Wrapper e rientra nella categoria dei pattern strutturali.

Penso non sia raro ritrovarsi con tante belle classi di libreria e non poterle usare perche’ incompatibili con l’interfaccia richiesta. Ecco che interviene l’adapter.

L’adapter va usato quando subentrano queste motivazioni:

  • una classe di una libreria non puo’ essere usata perche’ incompatibile con l’interfaccia richiesta dalla nostra applicazione
  • non e’ possibile (o non conveniente) cambiare l’interfaccia della libreria
  • non e’ possibile (o non conveniente) cambiare l’applicazione.

I partecipanti in questo Design Pattern sono:

  • Adaptee – classe con interfaccia che ha bisogno di essere adattata
  • ITarget – interfaccia che richiede il client
  • Client  – utilizza la classe che implementa Adaptee
  • Adapter – adatta l’interfacca Adaptee all’interfaccia ITarget

Realizzare l’Adapter significa che:

  • creiamo una classe Adapter che estende la classe Adaptee e implementa ITarget
  • il Client usa l’Adapter come se fosse l’oggetto di libreria

 

Diagramma UML Class Adapter
Diagramma UML Class Adapter

Meglio chiarire con un esempio. Abbiamo una classe (il nostro Client) che si occupa di effettuare calcoli sui grafi. Il Client si aspetta di avere a disposizione una classe libreria con la seguente interfaccia:

interface ITarget {

    public int getNodes();

    public int getDistance(Node a, Node b);

    public void setNodes(List nodes);
    //...
}

Abbiamo a disposizione una classe libreria, ma purtroppo l’interfaccia implementata e’ differente. Infatti;

interface IAdaptee { //metodi implementati da Adaptee

    public int getNodes(bool noNegativeNode);

    public bool setCurrentNode(Node node);

    public Node getCurrentNode();

    public int getDistanceFromCurrentNode(Node a);

    public void addNodes(Node node);

    public void clearNodes();
    //...
}

Si capisce subito che le differenze sono notevoli: il primo metodo richiede un parametro che indica se contare o no nodi negativi, non esiste un metodo getIstance() che prenda come parametri due nodi, non esiste un metodo setNodes() che prenda come parametro una lista di nodi che definisce l’intero grafo.

Invece di scartere questa libreria, possiamo decidere di usarla applicando l’Adapter. Per farlo creiamo una classe (Adapter) che implementa l’interfaccia richiesta dal Client (ITarget) e estende Adaptee. Nell’implementazione di ITarget utilizzeremo chiamate ai metodi di Adaptee.

public Adapter implements ITarget extends Adaptee {
 public void Adapter(){
 //...
 }

 public int getNodes(){
 return getNodes(false);
 }

 public int getDistance(Node a, Node b){
 Node oldNode = getCurrentNode();
 int distance = 0; //redun

 if(setCurrentNode(Node a)) {
 distance = getDistance(Node b);
 }
 setCurrentNode(oldNode);
 return distance;
 }

 //...

}

Quando ci occupiamo del design del nostro sistema, dobbiamo sempre considerare la potenza e la possibilita’ che possono derivare da un’architettura che sfrutta i vantaggi dell’Adapter; senza dimenticare se il gioco vale la candela: se l’adattare le interfaccie richiede piu’ tempo che scrivere una nuova implementazione forse non e’ la strada giusta l’Adapter.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *