Załóżmy, że masz dwa interfejsy:
interface Readable {
public void read();
}
interface Writable {
public void write();
}
W niektórych przypadkach obiekty implementujące mogą obsługiwać tylko jeden z nich, ale w wielu przypadkach implementacje będą obsługiwały oba interfejsy. Ludzie korzystający z interfejsów będą musieli zrobić coś takiego:
// 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();
Żadna z tych opcji nie jest szczególnie wygodna, tym bardziej, gdy rozważasz, że chcesz to jako parametr metody.
Jednym rozwiązaniem byłoby zadeklarowanie interfejsu owijania:
interface TheWholeShabam extends Readable, Writable {}
Ma to jednak jeden konkretny problem: wszystkie implementacje obsługujące zarówno Readable, jak i Writable muszą implementować TheWholeShabam, jeśli chcą być kompatybilne z osobami korzystającymi z interfejsu. Mimo że nie oferuje nic oprócz gwarantowanej obecności obu interfejsów.
Czy istnieje czyste rozwiązanie tego problemu, czy powinienem wybrać interfejs opakowania?
AKTUALIZACJA
W rzeczywistości często konieczne jest posiadanie obiektu, który jest zarówno czytelny, jak i zapisywalny, więc po prostu rozdzielenie obaw w argumentach nie zawsze jest czystym rozwiązaniem.
AKTUALIZACJA 2
(wyodrębnione jako odpowiedź, więc łatwiej jest komentować)
AKTUALIZACJA 3
Uwaga: podstawowym przypadkiem użycia tego nie są strumienie (chociaż one również muszą być obsługiwane). Strumienie wprowadzają bardzo konkretne rozróżnienie między nakładem a wynikiem, a obowiązki są wyraźnie rozdzielone. Pomyśl raczej o bytebuferze, w którym potrzebujesz jednego obiektu, do którego możesz pisać i czytać, jednego obiektu, który ma bardzo specyficzny stan związany z nim. Te obiekty istnieją, ponieważ są bardzo przydatne w niektórych rzeczach, takich jak asynchroniczne operacje we / wy, kodowanie ...
AKTUALIZACJA 4
Jedną z pierwszych rzeczy, które wypróbowałem, było to samo, co podana poniżej sugestia (sprawdź przyjętą odpowiedź), ale okazała się zbyt delikatna.
Załóżmy, że masz klasę, która musi zwrócić typ:
public <RW extends Readable & Writable> RW getItAll();
Jeśli wywołasz tę metodę, ogólna RW jest określana przez zmienną odbierającą obiekt, więc potrzebujesz sposobu na opisanie tej zmiennej.
MyObject myObject = someInstance.getItAll();
To zadziałałoby, ale po raz kolejny wiąże je z implementacją i może generować wyjątki klasycast w czasie wykonywania (w zależności od tego, co jest zwracane).
Dodatkowo, jeśli chcesz mieć zmienną klasową typu RW, musisz zdefiniować ogólną na poziomie klasy.