it-swarm.com.de

adapter-Ein reales Beispiel für das Adaptermuster

Ich möchte meinem Team die Verwendung von Adapter Pattern demonstrieren. Ich habe viele Bücher und Artikel online gelesen. Jeder zitiert ein Beispiel, das nützlich ist, um das Konzept zu verstehen (Shape, Speicherkarte, elektronische Adapter usw.), aber es gibt keine echte Fallstudie.

Können Sie bitte eine Fallstudie zu Adapter Pattern veröffentlichen?

p.s. Ich habe versucht, vorhandene Fragen in stackoverflow zu durchsuchen, konnte die Antwort aber nicht als neue Frage veröffentlichen. Wenn Sie wissen, dass es bereits eine Antwort darauf gibt, leiten Sie bitte um.

71
AksharRoop

Viele Beispiele für Adapter sind trivial oder unrealistisch ( Rechteck vs. LegacyRectangle, Ratchet vs. Socket , SquarePeg vs. RoundPeg , Duck vs. Türkei ). Schlimmer noch, viele zeigen nicht mehrere Adapter für verschiedene Adaptees ( jemand hat Javas Arrays.asList als Beispiel für das Adaptermuster genannt). Das Anpassen einer Schnittstelle von nur eine Klasse für die Zusammenarbeit mit einer anderen scheint ein schwaches Beispiel für das GoF-Adapter-Muster zu sein. Dieses Muster verwendet Vererbung und Polymorphismus. Daher würde man erwarten, dass ein gutes Beispiel mehrere Implementierungen von Adaptern für verschiedene Adaptoren zeigt. 

Das bestes Beispiel fand ich in Kapitel 26 von UML und Patterns anwenden: Eine Einführung in die objektorientierte Analyse und das Design und die iterative Entwicklung (3. Ausgabe) . Die folgenden Bilder stammen aus dem Lehrmaterial, das auf einer FTP-Site für das Buch bereitgestellt wird. 

Die erste zeigt, wie eine Anwendung mehrere Implementierungen (Anpassungselemente) verwenden kann, die funktional ähnlich sind (z. B. Steuerrechner, Abrechnungsmodule, Kreditautorisierungsdienste usw.), jedoch unterschiedliche APIs aufweisen. Wir möchten vermeiden, dass unser Domain-Layer-Code hartcodiert wird, um die verschiedenen Möglichkeiten zur Berechnung von Steuern, Nachverkäufen, Autorisieren von Kreditkartenanforderungen usw. zu behandeln. Dies sind alle externen Module, die variieren können und für die wir keine Änderungen vornehmen können Code. Der Adapter ermöglicht die harte Codierung im Adapter, während unser Code auf der Domänenschicht immer dieselbe Schnittstelle verwendet (die IWhateverAdapter-Schnittstelle).

Fig. 26.1

In der obigen Abbildung sehen wir nicht die eigentlichen Anpassungspunkte. Die folgende Abbildung zeigt jedoch, wie ein polymorpher Aufruf von postSale(...) in der IAccountingAdapter-Schnittstelle erfolgt, was zu einer Buchung des Verkaufs über SOAP an ein SAP-System führt. 

Fig. 26.2

71
Fuhrmanator

Konvertieren Sie eine Schnittstelle in eine andere Schnittstelle.

Ein reales Beispiel für das Adaptermuster

Um die Stromversorgung anzuschließen, haben wir weltweit verschiedene Schnittstellen.

enter image description here

42
Premraj

Wie macht man aus einer französischen Person eine normale Person ...

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

Beispiel

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

    service.PrintName(person);
    service.PrintName(new FrenchPersonAdapter(frenchPerson));
41
CountZero

Hier ist ein Beispiel, das die Konvertierung von analog data in digit data simuliert.

Es stellt einen Adapter bereit, der Float-Digit-Daten in Binärdaten umwandelt. Dies ist wahrscheinlich in der Praxis nicht nützlich, es hilft nur, das Konzept des Adapter-Musters zu erklären.


Code

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;

/**
 * <p>
 * Adapter - convert analog data to digit data.
 * </p>
 * 
 * @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);
    }
}

Code - Testfall

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

Abhängigkeit - über Maven

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.2</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.13</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.13</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.16</version>
    </dependency>

Wie testen?

Führen Sie einfach den Gerätetest aus.

11
Eric Wang

Das Adaptermuster fungiert als Brücke zwischen zwei inkompatiblen Schnittstellen . Dieses Muster beinhaltet eine einzige Klasse namens Adapter, die .__ ist. verantwortlich für die Kommunikation zwischen zwei unabhängigen oder inkompatiblen Schnittstellen.

Beispiele aus der Praxis können ein Sprachübersetzer oder ein mobiles Ladegerät sein. Mehr hier in diesem Youtube-Video:

Youtube - Adapter Design Pattern: Einführung

7
babu

Ein reales Beispiel ist Qt-Dbus.

Der qt-dbus verfügt über ein Dienstprogramm zum Generieren des Adapters und des Schnittstellencodes aus der bereitgestellten XML-Datei. Hier sind die Schritte dazu.

 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.

Das vollständige Beispiel von Qt-Dbus finden Sie hier - 

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

2

Eine PHP -Implementierung des Adapter-Musters, das zur Abwehr von Injektionsangriffen verwendet wird, finden Sie hier:

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

Ein interessanter Aspekt des Adapter-Musters besteht darin, dass es zwei Varianten gibt: Einen Klassenadapter, der auf mehrere Vererbung angewiesen ist, und einen Objektadapter, der auf die Komposition angewiesen ist. Das obige Beispiel beruht auf der Zusammensetzung.

2
Bill

Sie können das Adapter-Entwurfsmuster verwenden, wenn Sie unterschiedliche Schnittstellen mit ähnlichem Verhalten verwenden müssen (was normalerweise Klassen mit ähnlichem Verhalten, aber unterschiedlichen Methoden bedeutet). Ein Beispiel dafür wäre eine Klasse für den Anschluss an ein Samsung-Fernsehgerät und eine andere für den Anschluss an ein Sony-Fernsehgerät. Sie verfügen über ein gemeinsames Verhalten wie das Öffnen des Menüs, das Starten der Wiedergabe, die Verbindung zu einem Netzwerk usw. Die Bibliotheken verfügen jedoch über eine andere Implementierung (mit unterschiedlichen Methodennamen und Signaturen). Diese unterschiedlichen herstellerspezifischen Implementierungen werden in den UML-Diagrammen als Adaptee bezeichnet.

In Ihrem Code (in den UML-Diagrammen mit Client bezeichnet) können Sie die Methodenaufrufe der einzelnen Hersteller (oder Adaptee) anstelle von hartem Code verwenden, um eine generische Schnittstelle (mit Target in UML-Diagrammen), um diese ähnlichen Verhaltensweisen einzuschließen und nur mit einem Objekttyp zu arbeiten.

Die Adapters implementieren dann die Target - Schnittstelle, indem sie ihre Methodenaufrufe an die Adaptees delegieren, die über den Konstruktor an die Adapters übergeben werden.

Damit Sie dies in Java-Code realisieren können, habe ich ein sehr einfaches Projekt geschrieben, in dem genau das gleiche Beispiel verwendet wurde, das mit Adaptern für mehrere Smart-TV-Schnittstellen verwendet wurde. Der Code ist klein, gut dokumentiert und selbsterklärend, also erkundigen Sie sich, wie eine Implementierung in der realen Welt aussehen würde.

Laden Sie einfach den Code herunter und importieren Sie ihn als Maven-Projekt in Eclipse (oder Ihre bevorzugte IDE). Sie können den Code ausführen, indem Sie org.example.Main.Java ausführen. Denken Sie daran, dass es wichtig ist zu verstehen, wie Klassen und Interfaces zusammengefügt werden, um das Muster zu entwerfen. Ich habe auch einige falsche Adaptees im Paket com.thirdparty.libs erstellt. Ich hoffe es hilft!

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

2
Jaabax

Ein reales Beispiel kann das Melden von Dokumenten in einer Anwendung sein. Einfacher Code wie hier. 

Ich denke, Adapter sind sehr nützlich für die Programmierstruktur. 

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

Ergebnisse werden sein:

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

Es gibt viele Beispiele aus der Praxis für Adapter-Entwurfsmuster

Wie Handy-/Ladegerätadapter, Wasserleitungsreduzierer, Sprachübersetzer usw. Weitere Informationen finden Sie unter Adapterdesignmuster in Java

enter image description here

enter image description here

0
Rupesh Agrawal

Laut dem Buch "C # 3.0 Design Patterns" von Judith Bishop verwendete Apple das Adaptermuster, um Mac OS für die Zusammenarbeit mit Intel-Produkten anzupassen (in Kapitel 4 erläutert, Auszug hier 2 )

0
CBU

Verwenden Sie den Adapter, wenn Sie über eine Schnittstelle verfügen, die Sie nicht ändern können, die Sie jedoch verwenden müssen. Sehen Sie es sich an, als wären Sie der neue Mann in einem Büro, und Sie können nicht zulassen, dass die grauen Haare Ihren Regeln folgen - Sie müssen sich an ihre anpassen. Hier ist ein reales Beispiel aus einem realen Projekt, an dem ich irgendwann gearbeitet habe, wo die Benutzeroberfläche gegeben ist.

Sie haben eine Anwendung, die alle Zeilen in einer Datei in eine Listendatenstruktur einliest und sie in einem Raster anzeigt (nennen wir die zugrunde liegende Datenspeicher-Schnittstelle IDataStore). Der Benutzer kann durch diese Daten navigieren, indem er auf die Schaltflächen "Erste Seite", "Vorherige Seite", "Nächste Seite", "Letzte Seite" klickt. Alles funktioniert gut.

Jetzt muss die Anwendung mit Produktionsprotokollen verwendet werden, die zu groß sind, um in den Speicher eingelesen zu werden, aber der Benutzer muss noch durch sie navigieren! Eine Lösung wäre die Implementierung eines Cache, der die erste, nächste, vorherige und letzte Seite speichert. Was wir wollen, ist, wenn der Benutzer auf "Nächste Seite" klickt, wir geben die Seite aus dem Cache zurück und aktualisieren den Cache. Wenn sie auf die letzte Seite klicken, wird die letzte Seite aus dem Cache zurückgegeben. Im Hintergrund haben wir einen Filestream, der die ganze Magie übernimmt. Auf diese Weise haben wir im Gegensatz zur gesamten Datei nur vier Seiten im Speicher.

Sie können einen Adapter verwenden, um diese neue Cache-Funktion zu Ihrer Anwendung hinzuzufügen, ohne dass der Benutzer dies bemerkt. Wir erweitern den aktuellen IDataStore und nennen ihn CacheDataStore. Wenn die zu ladende Datei groß ist, verwenden wir CacheDataStore. Wenn wir eine Anfrage für die erste, nächste, vorherige und letzte Seite machen, werden die Informationen in unseren Cache geleitet.

Und wer weiß, morgen will der Chef die Dateien aus einer Datenbanktabelle lesen. Alles, was Sie tun, ist, IDataStore weiterhin auf SQLDataStore zu erweitern, wie Sie es für Cache getan haben, und die Verbindung im Hintergrund einrichten. Wenn Sie auf Nächste Seite klicken, generieren Sie die erforderliche SQL-Abfrage, um die nächsten paar hundert Zeilen aus der Datenbank abzurufen.

Im Wesentlichen hat sich die ursprüngliche Benutzeroberfläche der Anwendung nicht geändert. Wir haben einfach moderne und coole Funktionen angepasst, um sie unter Beibehaltung der älteren Benutzeroberfläche zu bearbeiten.

0
Justice O.

Das Beispiel von @Justice o spricht nicht eindeutig über das Adaptermuster. Erweiterung seiner Antwort - Wir haben eine vorhandene IDataStore-Schnittstelle, die unser Consumer-Code verwendet, und kann nicht geändert werden. Jetzt werden wir gebeten, eine coole neue Klasse aus der XYZ-Bibliothek zu verwenden, die das tut, was wir implementieren möchten, aber wir können diese Klasse nicht ändern, um unseren IDataStore zu erweitern. Das Problem ist bereits aufgetreten. Dies implementiert eine Schnittstelle, die unser Consumer-Code erwartet, z. B. IDataStore und die Verwendung einer Klasse aus der Bibliothek, deren Funktionen wir benötigen - ADAPTEE, als Mitglied in unserem ADAPTER, können wir das erreichen, was wir wollten.

0
rahil008