Angenommen, Sie haben zwei Schnittstellen:
interface Readable {
public void read();
}
interface Writable {
public void write();
}
In einigen Fällen können die implementierenden Objekte nur eines dieser Objekte unterstützen, in vielen Fällen unterstützen die Implementierungen jedoch beide Schnittstellen. Die Leute, die die Schnittstellen benutzen, müssen etwas tun wie:
// can't write to it without explicit casting
Readable myObject = new MyObject();
// can't read from it without explicit casting
Writable myObject = new MyObject();
// tight coupling to actual implementation
MyObject myObject = new MyObject();
Keine dieser Optionen ist besonders praktisch, insbesondere wenn Sie dies als Methodenparameter verwenden möchten.
Eine Lösung wäre, eine Wrapping-Schnittstelle zu deklarieren:
interface TheWholeShabam extends Readable, Writable {}
Dies hat jedoch ein spezifisches Problem: Alle Implementierungen, die Readable und Writable unterstützen, müssen TheWholeShabam implementieren, wenn sie mit Benutzern der Schnittstelle kompatibel sein sollen. Auch wenn es nichts anderes bietet als das garantierte Vorhandensein beider Schnittstellen.
Gibt es eine saubere Lösung für dieses Problem oder sollte ich mich für die Wrapper-Schnittstelle entscheiden?
AKTUALISIEREN
Es ist in der Tat oftmals erforderlich, ein Objekt zu haben, das sowohl lesbar als auch beschreibbar ist, so dass eine einfache Trennung der Bedenken in den Argumenten nicht immer eine saubere Lösung ist.
UPDATE2
(Als Antwort extrahiert, damit es einfacher ist, Kommentare abzugeben.)
UPDATE3
Bitte beachten Sie, dass der primäre Verwendungszweck hierfür nicht Streams sind (obwohl diese ebenfalls unterstützt werden müssen). Streams unterscheiden sehr genau zwischen Input und Output und es gibt eine klare Trennung der Verantwortlichkeiten. Stellen Sie sich stattdessen so etwas wie einen Bytepuffer vor, in dem Sie ein Objekt benötigen, in das Sie schreiben und aus dem Sie lesen können, ein Objekt, dem ein ganz bestimmter Status zugeordnet ist. Diese Objekte existieren, weil sie für einige Dinge wie asynchrone E / A, Codierungen usw. sehr nützlich sind.
UPDATE4
Eines der ersten Dinge, die ich versuchte, war das gleiche wie der unten angegebene Vorschlag (überprüfen Sie die akzeptierte Antwort), aber es erwies sich als zu zerbrechlich.
Angenommen, Sie haben eine Klasse, die den Typ zurückgeben muss:
public <RW extends Readable & Writable> RW getItAll();
Wenn Sie diese Methode aufrufen, wird die generische RW durch die Variable bestimmt, die das Objekt empfängt. Sie benötigen daher eine Möglichkeit, diese Variable zu beschreiben.
MyObject myObject = someInstance.getItAll();
Dies funktioniert, bindet es jedoch erneut an eine Implementierung und kann zur Laufzeit tatsächlich Ausnahmen für Klassencasts auslösen (je nachdem, was zurückgegeben wird).
Wenn Sie außerdem eine Klassenvariable vom Typ RW möchten, müssen Sie die generische Variable auf Klassenebene definieren.