Правильное поведение для методов интерфейса, которые не могут быть реализованы

#java

Вопрос:

Если у меня есть класс, которому необходимо реализовать интерфейс, но один или несколько методов этого интерфейса не имеют смысла в контексте этого конкретного класса, что мне делать?

Например, допустим, я реализую шаблон адаптера, в котором я хочу создать класс-оболочку, реализующий java.util.Map, путем обертывания некоторого неизменяемого объекта и представления его данных в виде пар ключ/значение. В этом случае методы put и putAll не имеют смысла, так как у меня нет возможности изменить базовый объект. Итак, вопрос в том, что должны делать эти методы?

Ответ №1:

Любой метод, который не может быть реализован в соответствии с семантикой интерфейса, должен вызывать исключение UnsupportedOperationException.

Комментарии:

1. Исключение UnsupportedOperationException обычно является правильным решением, если вы не знаете, что метод все равно будет вызван, и вы хотите сделать больше «без операции», и в этом случае возврат null или аналогичный-лучшее, что вы можете сделать.

2. Тот факт, что вам нужно это сделать, можно считать проблемой дизайна.

3. @Aidos, я согласен, если бы я разработал интерфейс, но есть некоторые сторонние библиотеки, интерфейсы которых не очень согласованны. Иногда я хочу использовать часть API, но другие его части просто не имеют смысла в контексте моего приложения.

Ответ №2:

Это зависит от вашего бизнес-кейса. 2 варианта:

Используйте то, что имеет больше смысла. Если вы ничего не делаете, вы не подчиняетесь контракту интерфейса. Однако создание исключения во время выполнения может нанести ущерб вызывающему коду. Таким образом, решение должно быть принято на основе того, как вы будете использовать класс. Другим вариантом было бы использовать более простой или другой интерфейс, если это возможно.

Обратите внимание, что библиотека Java использует маршрут исключений в конкретном случае коллекций, доступных только для чтения.


Ниже было отмечено, что исключение UnsupportedOperationException является частью платформы коллекций java. Если ваша ситуация выходит за рамки коллекций, и вас беспокоит семантика, вы можете использовать свои собственные NotImplementedException , или, если вы уже используете commons-lang, вы можете использовать их.

Ответ №3:

Эта коллекция только для чтения, уже предоставленная Java, вызывает исключение UnsupportedOperationException во время операций записи, что уже является неудачным взломом дизайна. Классы коллекции должны были быть написаны с отдельными интерфейсами только для чтения и только для записи, которые оба наследуются полным интерфейсом чтения и записи. Тогда вы знаете, что получаете.

Комментарии:

1. вы все равно столкнетесь с проблемой, когда API потребует интерфейса чтения/записи даже в тех случаях, когда подойдет только чтение. Но я согласен, гибкость была бы неплохой.

2. Этот API коллекций превратился бы в нечитаемый беспорядок, если бы было принято такое дизайнерское решение.

3. Проблема в конкретном случае Java связана не с интерфейсами, а с абстрактной коллекцией и т. Д. Вы не можете наследовать как от AbstractROCollection, так и от AbstractRWCollection, поэтому иерархия классов будет разделена на две части вверху. Вектор и только для чтения вектор будут очень отдаленно связаны.

Ответ №4:

Ваши два варианта на самом деле являются единственными:

  1. Ничего не делать.
  2. Создайте исключение.

У обоих есть недостатки. В первом случае, используя пустой метод, вы можете ввести программиста в заблуждение, заставив его подумать, что что-то случилось с вашими данными. Второй случай нарушает всю идею полиморфизма, присущего интерфейсам.

Ответ №5:

Обратите внимание, что исключение UnsupportedOperationException является допустимым только из-за определенного свойства платформы коллекций Java, что реализации разрешены для «безделья», реализующей часть интерфейса, потому что они неизменяемы.

Так что это нормально для put() (при условии, что все методы мутатора делают одно и то же), но карта, которая вызывает исключение UnsupportedOperationException из метода size (), будет просто нарушена. Если вы пытаетесь реализовать своего рода карту, которая не знает, насколько она велика, у вас могут возникнуть проблемы (хотя иногда вы можете возвращать целое число.MAX_VALUE).

Также обратите внимание, что в документации по классу для исключения UnsupportedOperationException говорится, что он является частью платформы коллекций Java. Вне рамок коллекций, исключение UnsupportedOperationException не ожидается и может привести к тому, что клиентский код просто не будет работать. Конечно, это исключение RuntimeException, но то, что вы можете его выбросить, не означает, что ваш метод будет работать, если он всегда будет работать.

Вместо этого вы могли бы либо переработать интерфейс (возможно, разделив его на два), либо переосмыслить, почему этот класс утверждает, что он является Foo, когда это явно не так, поскольку он не может делать то, что, как определено, может делать Foo.