Статьи

Уважаемый дизайнер API.

Некоторые API установлены в камне. Например, JDK. Или общедоступные API, например, между базой данных и клиентом базы данных (например, JDBC).

Это делает проектирование таких API довольно сложным, так как нужно много думать перед публикацией API. А это значит, что защита при разработке API — это хороший выбор.

Одной из защитных стратегий разработки API является постоянная работа с объектами параметров и возвращаемыми объектами. Мы уже писали об объектах параметров раньше . Давайте посмотрим на API, который не использует возвращаемые объекты, и почему это так ужасно:

База данных обновляемых операторов

При получении данных из базы данных мы получаем удобный API-тип, JDBC ResultSet . Другие языки, кроме Java, имеют схожие типы для моделирования результатов базы данных. В то время как ResultSet основном моделирует набор кортежей, он также содержит различные дополнительные полезные функции, такие как ResultSet.getMetaData() или ResultSet.getWarnings() , которые являются хитрыми задними дверями для передачи произвольной дополнительной информации с ResultSet .

Что лучше всего в этих типах результатов, так это то, что они могут быть расширены в обратном направлении. Новые методы и функции могут быть добавлены к этим типам результатов без изменения:

  • Любые существующие контракты
  • Любой существующий код клиента

Единственное, что может сломаться — это драйверы JDBC, но, начиная с Java 8, JDBC 4.2 и методов по умолчанию , это тоже дело прошлого.

При вызове оператора update в базе данных все выглядит иначе:

1
int count = stmt.executeUpdate();

Egh.

Значение count . Это оно? Как насчет любой информации, генерируемой триггером? Как насчет предупреждений (я знаю, они доступны из утверждения. Которые были изменены вызовом)?

Интересно, что это значение count являющееся целым count , похоже, беспокоило некоторых людей достаточно долго, чтобы метод был де-факто перегружен в JDBC 4.2:

1
long count = stmt.executeLargeUpdate();

Хм …

Я говорю «де-факто перегружен», потому что это технически перегрузка, но поскольку Java не поддерживает перегрузку по типу возвращаемого значения, имя также было изменено. ( Ну, JVM поддерживает это, но не язык ).

Когда вы прочитаете Javadoc метода executeUpdate() , вы заметите, что различные состояния закодированы в этом единственном примитивном значении:

Возвращает: либо (1) количество строк для операторов языка данных SQL (DML), либо (2) 0 для операторов SQL, которые ничего не возвращают

Более того, есть похожий метод getUpdateCount() , который кодирует еще более сложное состояние в один примитив:

текущий результат в виде количества обновлений; -1, если текущий результат является объектом ResultSet или результатов больше нет

Egh …

И как будто это не было достаточно плохо, вот очень специфический обходной путь для вышеупомянутого ограничения был реализован базой данных MySQL, которая кодирует различные состояния для операторов UPSERT как таковых:

При ON DUPLICATE KEY UPDATE значение затронутых строк на строку равно 1, если строка вставляется как новая строка, и 2, если существующая строка обновляется. Смотрите здесь

Если производительность не имеет значения, всегда возвращайте ссылочный тип!

Это действительно плохо. Вызов проходит по проводам к базе данных. Это по сути медленно. Мы бы ничего не потеряли, если бы у нас был UpdateResult данных UpdateResult в результате executeUpdate() . Другой пример — String.indexOf(...) который кодирует «not found» как -1 по соображениям производительности.

Ошибка происходит не только в этих старых API, которые предшествуют объектно-ориентированному программированию. Это повторяется снова в более новых API во многих приложениях, когда первое, что приходит на ум как полезный метод, — это примитивное значение (или, что еще хуже: void).

Если вы пишете свободный API (например, Java 8 Stream API или jOOQ) , это не будет проблемой, поскольку API всегда возвращает сам тип, чтобы позволить пользователям связывать вызовы методов.

В других ситуациях тип возвращаемого значения очень понятен, потому что вы не выполняете никаких побочных действий. Но если вы это сделаете, пожалуйста, подумайте еще раз, действительно ли вы хотите вернуть просто примитив. Если вам придется поддерживать API в течение длительного времени, вы можете просто пожалеть об этом через несколько лет.

Читайте об API дизайн