Есть целый ряд различных вариантов/подходов, которые часто принимаются:
Блокировка как API вы показали. Это очень простой API для использования, и параллелизм может быть достигнут путем вызова API из многопоточного приложения.
Получение/регистрация обработчиков в асинхронных операциях. Это иногда предоставляется в сочетании с API блокировки (и, фактически, может быть реализовано с точки зрения API блокировки просто путем создания фонового потока, а затем последующего вызова обработчика в конце).
Возвращения будущего или ListenableFuture объекта, который делает интерфейс более идиоматический Java-эск (путем возврата данных в позиции возврата типа), но представляя конечный результат, а не сразу же доступен результат. Будущее можно использовать для блокировки или неблокирования.
Лично моя рекомендация здесь будет:
interface EmployeeDatabase {
interface StringWhereClause {
ListQueryBuilder is(String value);
ListQueryBuilder contains(String value);
ListQueryBUilder matchesRegex(String regex);
}
interface IntWhereClause {
ListQueryBuilder is(int value);
ListQueryBuilder isInRange(int min, int max);
ListQueryBuilder isGreaterThan(int value);
ListQueryBUilder isLessThan(int value);
ListQueryBuilder isGreaterThanOrEqualTo(int value);
ListQueryBUilder isLessThanOrEqualTo(int value);
}
// ... matchers for other types of properties ...
interface ListQueryBuilder {
// Generic restrict methods
StringWhereClause whereStringProperty(String propertyName);
IntWhereClause whereIntProperty(String propertyName);
// ...
// Named restrict methods
StringWhereClause whereName();
StringWhereClause whereJobTitle();
IntWhereClause whereEmployeeNumber();
// ...
ListQueryBuilder limit(long maximumSize);
ListQueryBuilder offset(long index);
ResultSet<Employee> fetch();
}
ListQueryBuilder list();
ListenableFuture<Employee> getById(Key key);
ListenableFuture<KeyOrError> add(Employee employee);
ListenableFuture<Status> update(Key key, Employee employee);
ListenableFuture<Status> delete(Key key);
}
С:
interface ResultSet<T> {
Iterable<T> asIterable();
// ... other methods ...
}
interface KeyOrError {
boolean isError();
boolean isKey();
Key getKey();
Throwable getError();
}
interface Status {
boolean isOk();
boolean isError();
Throwable getError();
void verifyOk();
}
В принципе, идея заключается в том, что введение в базу данных возвращает ключевой объект (или ошибка, если неудачный). Этот ключ можно использовать для извлечения, удаления или обновления записи в базе данных.Эти операции (добавление, обновление, удаление и getById) имеют единственный результат, и в этом случае вместо T
используется ListenableFuture<T>
; этот будущий объект позволяет блокировать (путем вызова .get()
на будущий объект) или для асинхронного извлечения объекта (путем регистрации обратного вызова, который будет вызываться, когда результат будет готов).
Для операций list-y существует множество способов, по которым список может быть отфильтрован, подселеклен, отсортирован и т. Д. Чтобы предотвратить комбинаторный взрыв различных различных перегрузок, мы используем builder pattern, чтобы эти ограничения могли применяется в нескольких комбинациях. Короче говоря, интерфейс построителя обеспечивает способ привязки к нулю или более параметров (сортировки, фильтры, ограничения и т. Д.) Для применения операции поиска до вызова fetch()
, который вызывает выполнение запроса списка, и возвращает ResultSet
. Эта операция возвращает ResultSet
, а не ListenableFuture
, так как результаты не все возвращаются сразу (например, они могут возвращаться из базы данных потоковым способом); ResultSet
- это фактически интерфейс с аналогичным поведением с ListenableFuture
, но для списков элементов (где элементы могут быть готовы в разное время). Для удобства важно иметь возможность легко перебирать содержимое ResultSet (например, путем предоставления адаптера Iterable
ResultSet); однако, вероятно, вам также захочется добавить другие методы, которые позволят вам выполнять другие типы асинхронной обработки на ResultSet; например, вам может понадобиться ListenableFuture<T> reduce(T initialValue, ReduceFunction<T> reducer)
для агрегирования элементов в наборе результатов и предоставления будущего объекта, представляющего возможное завершение этого.
Спасибо! Не могли бы вы добавить несколько строк объяснения к вашему примеру? – Anthony