Verbinden Sie ungleiche Schnittstellen in Java mit dem Adapter Design Pattern
Erfahren Sie, wie das Adapter Design Pattern in Java unvereinbare Schnittstellen harmonisch zusammenbringt. Entdecken Sie realistische Anwendungen und Implementierungen dieses nützlichen Musters, von Handy-Ladegeräten bis zu Java-Klassen.
Ein Beispiel aus dem echten Leben
Ein großartiges Beispiel für den Adapter Design Pattern im realen Leben ist ein Handy-Ladegerät. Die Handybatterie benötigt 3 Volt zum Aufladen, aber die normale Steckdose liefert entweder 120 Volt (USA) oder 240 Volt (Indien). Das Handy-Ladegerät fungiert also als Adapter zwischen der Handy-Ladebuchse und der Wandsteckdose.
Implementierung eines Multi-Adapters
Wir werden versuchen, einen Multi-Adapter mithilfe des Adapter Design Patterns in diesem Tutorial zu implementieren. Dazu werden zunächst zwei Klassen benötigt: Volt
(um Volt zu messen) und Socket
(um konstante 120 Volt zu erzeugen).
package com.journaldev.design.adapter;
public class Volt {
private int volts;
public Volt(int v){
this.volts = v;
}
public int getVolts() {
return volts;
}
public void setVolts(int volts) {
this.volts = volts;
}
}
package com.journaldev.design.adapter;
public class Socket {
public Volt getVolt(){
return new Volt(120);
}
}
Adapter-Schnittstelle erstellen
Nun möchten wir einen Adapter erstellen, der 3 Volt, 12 Volt und standardmäßig 120 Volt erzeugen kann. Dafür erstellen wir eine Adapter-Schnittstelle mit diesen Methoden:
package com.journaldev.design.adapter;
public interface SocketAdapter {
public Volt get120Volt();
public Volt get12Volt();
public Volt get3Volt();
}
Es gibt zwei Ansätze zur Implementierung des Adapter Patterns: den Klassenadapter und den Objektadapter. In beiden Ansätzen wird jedoch dasselbe Ergebnis erzielt.
Klassenadapter – Implementierung
Hier ist die Implementierung des Klassenadapters:
package com.journaldev.design.adapter;
// Verwendung der Vererbung für das Adaptermuster
public class SocketClassAdapterImpl extends Socket implements SocketAdapter {
@Override
public Volt get120Volt() {
return getVolt();
}
@Override
public Volt get12Volt() {
Volt v = getVolt();
return convertVolt(v, 10);
}
@Override
public Volt get3Volt() {
Volt v = getVolt();
return convertVolt(v, 40);
}
private Volt convertVolt(Volt v, int i) {
return new Volt(v.getVolts() / i);
}
}
Objektadapter – Implementierung
Hier ist die Implementierung des Objektadapters:
package com.journaldev.design.adapter;
public class SocketObjectAdapterImpl implements SocketAdapter {
// Verwendung der Komposition für das Adaptermuster
private Socket sock = new Socket();
@Override
public Volt get120Volt() {
return sock.getVolt();
}
@Override
public Volt get12Volt() {
Volt v = sock.getVolt();
return convertVolt(v, 10);
}
@Override
public Volt get3Volt() {
Volt v = sock.getVolt();
return convertVolt(v, 40);
}
private Volt convertVolt(Volt v, int i) {
return new Volt(v.getVolts() / i);
}
}
Beachten Sie, dass beide Adapterimplementierungen fast gleich sind und die SocketAdapter
-Schnittstelle implementieren können. Die Adapter-Schnittstelle kann auch eine abstrakte Klasse sein.
Testprogramm
Hier ist ein Testprogramm, um unsere Implementierung des Adapter Design Patterns zu verwenden:
package com.journaldev.design.test;
import com.journaldev.design.adapter.SocketAdapter;
import com.journaldev.design.adapter.SocketClassAdapterImpl;
import com.journaldev.design.adapter.SocketObjectAdapterImpl;
import com.journaldev.design.adapter.Volt;
public class AdapterPatternTest {
public static void main(String[] args) {
testClassAdapter();
testObjectAdapter();
}
private static void testObjectAdapter() {
SocketAdapter sockAdapter = new SocketObjectAdapterImpl();
Volt v3 = getVolt(sockAdapter, 3);
Volt v12 = getVolt(sockAdapter, 12);
Volt v120 = getVolt(sockAdapter, 120);
System.out.println("v3 volts using Object Adapter=" + v3.getVolts());
System.out.println("v12 volts using Object Adapter=" + v12.getVolts());
System.out.println("v120 volts using Object Adapter=" + v120.getVolts());
}
private static void testClassAdapter() {
SocketAdapter sockAdapter = new SocketClassAdapterImpl();
Volt v3 = getVolt(sockAdapter, 3);
Volt v12 = getVolt(sockAdapter, 12);
Volt v120 = getVolt(sockAdapter, 120);
System.out.println("v3 volts using Class Adapter=" + v3.getVolts());
System.out.println("v12 volts using Class Adapter=" + v12.getVolts());
System.out.println("v120 volts using Class Adapter=" + v120.getVolts());
}
private static Volt getVolt(SocketAdapter sockAdapter, int i) {
switch (i){
case 3: return sockAdapter.get3Volt();
case 12: return sockAdapter.get12Volt();
case 120: return sockAdapter.get120Volt();
default: return sockAdapter.get120Volt();
}
}
}
Wenn wir das oben stehende Testprogramm ausführen, erhalten wir die folgende Ausgabe:
v3 volts using Class Adapter=3
v12 volts using Class Adapter=12
v120 volts using Class Adapter=120
v3 volts using Object Adapter=3
v12 volts using Object Adapter=12
v120 volts using Object Adapter=120
Zusammenfassung
Der Adapter Design Pattern ermöglicht es, zwei nicht zusammenhängende Schnittstellen zusammenarbeiten zu lassen, indem er ein Adapterobjekt zwischen sie stellt. In diesem Blogbeitrag haben wir gesehen, wie der Adapter Pattern in Java implementiert werden kann, sowohl als Klassenadapter als auch als Objektadapter. Dieses Design Pattern ist besonders nützlich, wenn Sie mit Legacy-Code arbeiten oder Schnittstellen von Drittanbietern verwenden müssen.
Beispiel in der JDK
Einige Beispiele für den Adapter Design Pattern in JDK-Klassen sind:
java.util.Arrays#asList()
java.io.InputStreamReader(InputStream)
(gibt einen Reader zurück)java.io.OutputStreamWriter(OutputStream)
(gibt einen Writer zurück)