adattatore: qualsiasi esempio reale di Pattern adattatore

Voglio dimostrare l’uso di Adapter Pattern al mio team. Ho letto molti libri e articoli online. Tutti citano un esempio che è utile per comprendere il concetto (Shape, Memory Card, Electronic Adapter ecc.), Ma non esiste un case study reale.

Potete per favore condividere qualsiasi studio di caso su Adapter Pattern?

ps Ho provato a cercare le domande esistenti su StackOverflow, ma non ho trovato la risposta in modo da postarla come una nuova domanda. Se sai che esiste già una risposta per questo, ti preghiamo di redirect.

Molti esempi di Adapter sono banali o irrealistici ( Rettangolo vs. LegacyRectangle, Ratchet vs. Socket , SquarePeg vs RoundPeg , Duck vs. Turkey ). Peggio ancora, molti non mostrano più adattatori per adattamenti diversi ( qualcuno ha citato Java Arrays.asList come esempio del modello dell’adattatore ). Adattare un’interfaccia di una sola class per lavorare con un’altra sembra un debole esempio del modello dell’adattatore GoF. Questo modello utilizza ereditarietà e polimorfismo, quindi ci si potrebbe aspettare un buon esempio per mostrare più implementazioni di adattatori per adattamenti diversi .

L’ esempio migliore che ho trovato è il Capitolo 26 di Applicazione di UML e Pattern: Introduzione all’analisi orientata agli oggetti e progettazione e sviluppo iterativo (terza edizione) . Le seguenti immagini provengono dal materiale per l’istruttore fornito su un sito FTP per il libro.

Il primo mostra come un’applicazione può utilizzare più implementazioni (adattamenti) che sono funzionalmente simili (ad esempio, calcolatori delle imposte, moduli contabili, servizi di authorization del credito, ecc.) Ma hanno API diverse. Vogliamo evitare l’hard-coding del nostro codice a livello di dominio per gestire i diversi modi possibili di calcolare le tasse, post-vendita, autorizzare richieste di carte di credito, ecc. Questi sono tutti moduli esterni che potrebbero variare e per i quali non possiamo modificare codice. L’adattatore ci consente di eseguire l’hard-coding nell’adattatore, mentre il nostro codice a livello di dominio utilizza sempre la stessa interfaccia (l’interfaccia IWhateverAdapter).

Fig. 26.1

Non vediamo nella figura sopra gli adattamenti effettivi. Tuttavia, la figura seguente mostra come viene eseguita una chiamata polimorfa a postSale(...) nell’interfaccia IAccountingAdapter, che si traduce in una pubblicazione della vendita tramite SOAP in un sistema SAP.

Fig. 26.2

Convertire un’interfaccia in un’altra interfaccia.

Qualsiasi esempio reale di Pattern adattatore

Al fine di colbind il potere, abbiamo diverse interfacce in tutto il mondo. Usando l’adattatore possiamo connetterci facilmente come saggio.

inserisci la descrizione dell'immagine qui

Come trasformare una persona francese in una persona normale …

  public interface IPerson { string Name { get; set; } } public interface IFrenchPerson { string Nom { get; set; } } public class Person : IPerson { public string Name { get; set; } } public class FrenchPerson : IFrenchPerson { public string Nom { get; set; } } public class PersonService { public void PrintName(IPerson person) { Debug.Write(person.Name); } } public class FrenchPersonAdapter : IPerson { private readonly IFrenchPerson frenchPerson; public FrenchPersonAdapter(IFrenchPerson frenchPerson) { this.frenchPerson = frenchPerson; } public string Name { get { return frenchPerson.Nom; } set { frenchPerson.Nom = value; } } } 

Esempio

  var service = new PersonService(); var person = new Person(); var frenchPerson = new FrenchPerson(); service.PrintName(person); service.PrintName(new FrenchPersonAdapter(frenchPerson)); 

Ecco un esempio che simula la conversione di analog data di digit data .

Fornisce un adattatore che converte dati in virgola mobile in dati binari, probabilmente non è utile nel mondo reale, ma aiuta solo a spiegare il concetto di modello di adattatore.


Codice

AnalogSignal.java

 package eric.designpattern.adapter; public interface AnalogSignal { float[] getAnalog(); void setAnalog(float[] analogData); void printAnalog(); } 

DigitSignal.java

 package eric.designpattern.adapter; public interface DigitSignal { byte[] getDigit(); void setDigit(byte[] digitData); void printDigit(); } 

FloatAnalogSignal.java

 package eric.designpattern.adapter; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FloatAnalogSignal implements AnalogSignal { private Logger logger = LoggerFactory.getLogger(this.getClass()); private float[] data; public FloatAnalogSignal(float[] data) { this.data = data; } @Override public float[] getAnalog() { return data; } @Override public void setAnalog(float[] analogData) { this.data = analogData; } @Override public void printAnalog() { logger.info("{}", Arrays.toString(getAnalog())); } } 

BinDigitSignal.java

 package eric.designpattern.adapter; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BinDigitSignal implements DigitSignal { private Logger logger = LoggerFactory.getLogger(this.getClass()); private byte[] data; public BinDigitSignal(byte[] data) { this.data = data; } @Override public byte[] getDigit() { return data; } @Override public void setDigit(byte[] digitData) { this.data = digitData; } @Override public void printDigit() { logger.info("{}", Arrays.toString(getDigit())); } } 

AnalogToDigitAdapter.java

 package eric.designpattern.adapter; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 

* Adapter - convert analog data to digit data. *

* * @author eric * @date Mar 8, 2016 1:07:00 PM */ public class AnalogToDigitAdapter implements DigitSignal { public static final float DEFAULT_THRESHOLD_FLOAT_TO_BIN = 1.0f; // default threshold, private Logger logger = LoggerFactory.getLogger(this.getClass()); private AnalogSignal analogSignal; private byte[] digitData; private float threshold; private boolean cached; public AnalogToDigitAdapter(AnalogSignal analogSignal) { this(analogSignal, DEFAULT_THRESHOLD_FLOAT_TO_BIN); } public AnalogToDigitAdapter(AnalogSignal analogSignal, float threshold) { this.analogSignal = analogSignal; this.threshold = threshold; this.cached = false; } @Override public synchronized byte[] getDigit() { if (!cached) { float[] analogData = analogSignal.getAnalog(); int len = analogData.length; digitData = new byte[len]; for (int i = 0; i < len; i++) { digitData[i] = floatToByte(analogData[i]); } } return digitData; } // not supported, should set the inner analog data instead, @Override public void setDigit(byte[] digitData) { throw new UnsupportedOperationException(); } public synchronized void setAnalogData(float[] analogData) { invalidCache(); this.analogSignal.setAnalog(analogData); } public synchronized void invalidCache() { cached = false; digitData = null; } @Override public void printDigit() { logger.info("{}", Arrays.toString(getDigit())); } // float -> byte convert, private byte floatToByte(float f) { return (byte) (f >= threshold ? 1 : 0); } }

Codice – Test case

AdapterTest.java

 package eric.designpattern.adapter.test; import java.util.Arrays; import junit.framework.TestCase; import org.junit.Test; import eric.designpattern.adapter.AnalogSignal; import eric.designpattern.adapter.AnalogToDigitAdapter; import eric.designpattern.adapter.BinDigitSignal; import eric.designpattern.adapter.DigitSignal; import eric.designpattern.adapter.FloatAnalogSignal; public class AdapterTest extends TestCase { private float[] analogData = { 0.2f, 1.4f, 3.12f, 0.9f }; private byte[] binData = { 0, 1, 1, 0 }; private float[] analogData2 = { 1.2f, 1.4f, 0.12f, 0.9f }; @Test public void testAdapter() { AnalogSignal analogSignal = new FloatAnalogSignal(analogData); analogSignal.printAnalog(); DigitSignal digitSignal = new BinDigitSignal(binData); digitSignal.printDigit(); // adapter AnalogToDigitAdapter adAdapter = new AnalogToDigitAdapter(analogSignal); adAdapter.printDigit(); assertTrue(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit())); adAdapter.setAnalogData(analogData2); adAdapter.printDigit(); assertFalse(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit())); } } 

Dipendenza – via Maven

   junit junit 4.8.2   org.slf4j slf4j-api 1.7.13   org.slf4j slf4j-log4j12 1.7.13   log4j log4j 1.2.16  

Come testare

Basta eseguire il test dell’unità.

Il modello dell’adattatore funziona come un ponte tra due interfacce incompatibili. Questo modello coinvolge una singola class chiamata adattatore che è responsabile della comunicazione tra due interfacce indipendenti o incompatibili.

Gli esempi del mondo reale potrebbero essere un traduttore di lingue o un caricatore mobile. Altro qui in questo video di youtube:

Youtube – Pattern di progettazione dell’adapter: Introduzione

È ansible trovare un’implementazione PHP del modello Adapter utilizzato come difesa dagli attacchi di iniezione qui:

http://www.php5dp.com/category/design-patterns/adapter-composition/

Uno degli aspetti interessanti del modello Adapter è che è disponibile in due versioni: un adattatore di class basato su ereditarietà multipla e un adattatore oggetti che si basa sulla composizione. L’esempio sopra si basa sulla composizione.

Un esempio reale è Qt-Dbus.

Qt-dbus ha un’utilità per generare l’adattatore e il codice di interfaccia dal file xml fornito. Ecco i passaggi per farlo.

  1. Create the xml file - this xml file should have the interfaces that can be viewed by the qdbus-view in the system either on the system or session bus. 2.With the utility - qdbusxml2cpp , you generate the interface adaptor code. This interface adaptor does the demarshalling of the data that is received from the client. After demarshalling, it invokes the user defined - custom methods ( we can say as adaptee). 3. At the client side, we generate the interface from the xml file. This interface is invoked by the client. The interface does the marshalling of the data and invokes the adaptor interface. As told in the point number 2, the adaptor interface does the demarshalling and calls the adaptee - user defined methods. 

Qui puoi vedere l’esempio completo di Qt-Dbus –

http://www.tune2wizard.com/linux-qt-signals-and-slots-qt-d-bus/

Un esempio reale può essere la segnalazione di documenti in un’applicazione. Codice semplice come qui

Gli adattatori che ritengo siano molto utili per la struttura di programmazione.

 class WordAdaptee implements IReport{ public void report(String s) { System.out.println(s +" Word"); } } class ExcellAdaptee implements IReport{ public void report(String s) { System.out.println(s +" Excel"); } } class ReportAdapter implements IReport{ WordAdaptee wordAdaptee=new WordAdaptee(); @Override public void report(String s) { wordAdaptee.report(s); } } interface IReport { public void report(String s); } public class Main { public static void main(String[] args) { //create the interface that client wants IReport iReport=new ReportAdapter(); //we want to write a report both from excel and world iReport.report("Trial report1 with one adaptee"); //we can directly write the report if one adaptee is avaliable //assume there are N adaptees so it is like in our example IReport[] iReport2={new ExcellAdaptee(),new WordAdaptee()}; //here we can use Polymorphism here for (int i = 0; i < iReport2.length; i++) { iReport2[i].report("Trial report 2"); } } } 

I risultati saranno:

 Trial report1 with one adaptee Word Trial report 2 Excel Trial report 2 Word 

È ansible utilizzare il modello di progettazione dell’adattatore quando si ha a che fare con interfacce diverse con comportamenti simili (che in genere indicano classi con un comportamento simile ma con metodi diversi). Un esempio di questo sarebbe una class per connettersi a un televisore Samsung e un altro per connettersi a un televisore Sony. Condivideranno comportamenti comuni come il menu aperto, l’avvio della riproduzione, la connessione a una rete e così via, ma ciascuna libreria avrà un’implementazione diversa (con diversi nomi di metodi e firme). Queste diverse implementazioni specifiche del fornitore si chiamano Adaptee nei diagrammi UML.

Quindi, nel tuo codice (chiamato Client nei diagrammi UML), invece del codice rigido il metodo chiama da ciascun fornitore (o Adaptee ), potresti quindi creare un’interfaccia generica (chiamata Target nei diagrammi UML) per avvolgere questi comportamenti simili e lavorare con un solo tipo di object.

Gli adattatori implementeranno quindi l’interfaccia di destinazione delegando le sue chiamate di metodo agli adattamenti che vengono passati agli adattatori tramite il costruttore.

Per realizzarlo in codice Java, ho scritto un progetto molto semplice usando esattamente lo stesso esempio sopra menzionato usando gli adattatori per gestire più interfacce TV intelligenti. Il codice è piccolo, ben documentato e autoesplicativo, quindi scavalo per vedere come sarebbe l’implementazione di un mondo reale.

Basta scaricare il codice e importarlo in Eclipse (o il tuo IDE preferito) come progetto Maven. È ansible eseguire il codice eseguendo org.example.Main.java . Ricorda che la cosa importante qui è capire come le classi e le interfacce vengono assemblate insieme per progettare il modello. Ho anche creato alcuni adattamenti falsi nel pacchetto com.thirdparty.libs . Spero che sia d’aiuto!

https://github.com/Dannemann/java-design-patterns

Usa l’adattatore quando hai un’interfaccia che non puoi cambiare, ma che devi usare. Guardalo come se fossi il nuovo ragazzo in un ufficio e non puoi fare in modo che i capelli grigi seguano le tue regole – devi adattarti al loro. Ecco un esempio reale tratto da un progetto reale su cui ho lavorato a volte in cui l’interfaccia utente è un dato di fatto.

Si dispone di un’applicazione che legge tutte le righe di un file in una struttura di dati Elenco e le visualizza in una griglia (chiamiamo l’interfaccia di archiviazione dati sottostante IDataStore). L’utente può navigare attraverso questi dati facendo clic sui pulsanti “Prima pagina”, “Pagina precedente”, “Pagina successiva”, “Ultima pagina”. Tutto funziona bene

Ora l’applicazione deve essere utilizzata con registri di produzione che sono troppo grandi per essere letti in memoria, ma l’utente deve comunque navigare attraverso di essa! Una soluzione potrebbe essere quella di implementare una cache che memorizza la prima pagina, la successiva, la precedente e l’ultima. Quello che vogliamo è quando l’utente fa clic su “Pagina successiva”, restituiamo la pagina dalla cache e aggiorniamo la cache; quando fanno clic sull’ultima pagina, restituiamo l’ultima pagina dalla cache. Sullo sfondo abbiamo un filestream che fa tutta la magia. In questo modo abbiamo solo quattro pagine in memoria anziché l’intero file.

È ansible utilizzare un adattatore per aggiungere questa nuova funzione di cache all’applicazione senza che l’utente se ne accorga. Estendiamo l’attuale IDataStore e lo chiamiamo CacheDataStore. Se il file da caricare è grande, usiamo CacheDataStore. Quando facciamo una richiesta per le pagine First, Next, Previous e Last, le informazioni vengono indirizzate alla nostra cache.

E chissà, domani il capo vuole iniziare a leggere i file da una tabella di database. Tutto ciò che fai è ancora estendere IDataStore a SQLDataStore come hai fatto per Cache, impostare la connessione in background. Quando fanno clic su Pagina successiva, si genera la query sql necessaria per recuperare le centinaia di righe successive dal database.

In sostanza, l’interfaccia originale dell’applicazione non è cambiata. Abbiamo semplicemente adattato funzioni moderne e interessanti per lavorarci preservando l’interfaccia legacy.

L’esempio di @Justice o non parla chiaramente del modello dell’adattatore. Estendere la sua risposta: abbiamo un’interfaccia IDataStore esistente che il nostro codice utente utilizza e non possiamo modificarla. Ora ci viene chiesto di utilizzare una nuova class fresca dalla libreria XYZ che esegue ciò che vogliamo implementare, ma ma, non possiamo cambiare quella class per estendere il nostro IDataStore, visto il problema già? Creando una nuova class – ADAPTER, che implementa l’interfaccia che il nostro codice consumer si aspetta, ovvero IDataStore e utilizzando la class dalla libreria di cui abbiamo bisogno di disporre – ADAPTEE, come membro nel nostro ADAPTER, possiamo ottenere ciò che volevamo.

Schema di progettazione dell’adattatore nell’esempio java in tempo reale:

  1. Un lettore di tabs che funge da adattatore tra la scheda di memoria e un laptop. Inserisci la scheda di memoria nel lettore di tabs e nel lettore di tabs nel computer portatile in modo che la scheda di memoria possa essere letta via laptop.
  2. Il caricatore mobile che funge da adattatore tra una presa di ricarica mobile e una presa a muro. La batteria mobile ha bisogno di 3 volt per caricare, ma la presa normale produce 240V. Quindi il caricabatterie funziona come un adattatore tra la presa di ricarica mobile e la presa a muro.

Per ulteriori riferimenti segui il link sottostante

Questo è un esempio di implementazione dell’adattatore:

 interface NokiaInterface { chargementNokia(x:boolean):void } class SamsungAdapter implements NokiaInterface { //nokia chargement adapted to samsung chargementNokia(x:boolean){ const old= new SamsungCharger(); let y:number = x ? 20 : 1; old.charge(y); } } class SamsungCharger { charge(x:number){ console.log("chrgement x ==>", x); } } function main() { //charge samsung with nokia charger const adapter = new SamsungAdapter(); adapter.chargementNokia(true); }