Предположим, у вас есть два интерфейса:
interface Readable {
public void read();
}
interface Writable {
public void write();
}
В некоторых случаях реализующие объекты могут поддерживать только один из них, но во многих случаях реализации будут поддерживать оба интерфейса. Люди, которые используют интерфейсы, должны сделать что-то вроде:
// 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();
Ни одна из этих опций не очень удобна, тем более, если учесть, что вы хотите это в качестве параметра метода.
Одним из решений было бы объявить интерфейс упаковки:
interface TheWholeShabam extends Readable, Writable {}
Но это имеет одну конкретную проблему: все реализации, которые поддерживают как Readable, так и Writable, должны реализовывать TheWholeShabam, если они хотят быть совместимыми с людьми, использующими интерфейс. Хотя он не предлагает ничего, кроме гарантированного наличия обоих интерфейсов.
Есть чистое решение этой проблемы или я должен пойти на интерфейс оболочки?
ОБНОВИТЬ
На самом деле часто бывает необходимо иметь объект, который может быть читаем и доступен для записи, поэтому простое разделение проблем в аргументах не всегда является чистым решением.
UPDATE2
(извлечено как ответ, так что проще комментировать)
Update3
Пожалуйста, имейте в виду, что основной сценарий использования этого не потоки (хотя они тоже должны поддерживаться). Потоки делают очень четкое различие между входом и выходом, и существует четкое разделение обязанностей. Скорее, подумайте о чем-то вроде байтового буфера, где вам нужен один объект, в который вы можете писать и читать, один объект, к которому прикреплено очень специфическое состояние. Эти объекты существуют, потому что они очень полезны для некоторых вещей, таких как асинхронный ввод-вывод, кодировки, ...
UPDATE4
Одна из первых вещей, которые я попробовал, была такой же, как предложение, приведенное ниже (проверьте принятый ответ), но оно оказалось слишком хрупким.
Предположим, у вас есть класс, который должен возвращать тип:
public <RW extends Readable & Writable> RW getItAll();
Если вы вызываете этот метод, общая RW определяется переменной, получающей объект, поэтому вам нужен способ описать эту переменную.
MyObject myObject = someInstance.getItAll();
Это будет работать, но еще раз связывает его с реализацией и может фактически генерировать исключения classcastexception во время выполнения (в зависимости от того, что возвращается).
Кроме того, если вам нужна переменная класса типа RW, вам нужно определить универсальный тип на уровне класса.