Статьи

Мажоритарной

Часто мы пишем код, чтобы выработать первый ответ из множества доступных. Давайте посмотрим на это в Java.

01
02
03
04
05
06
07
08
09
10
11
12
public Widget getAppropriateWidget(CustomerRequest request) {
    if (shelfstock.contains(request.getBarcode()) {
        return new ShelfWidget();
    }
    if (backroomStock.contains(request.getBarcode()) {
        return new BackroomWidget();
    }
    if (supplier.contains(request.getEan()) {
        return new SupplierWidget();
    }
    return null;
}

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

Давайте также представим, что вызовы содержимого по какой-то причине дороги — возможно, каждый из этих объектов скрывает веб-сервис или сложный запрос к базе данных.

Давайте начнем с рефакторинга приведенного выше кода двумя способами. Давайте сделаем так, чтобы он использовал Optional , и давайте заставим его использовать подпрограммы для каждого из методов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public Optional<Widget> getAppropriateWidget(CustomerRequest request) {
    Optional<Widget> shelfWidget =
        getShelfWidget(request);
    if (shelfWidget.isPresent()) {
        return shelfWidget;
    }
    Optional<Widget> backroomWidget =
        getBackroomWidget(request);
    if (backroomWidget.isPresent()) {
        return backroomWidget;
    }
    Optional<Widget> supplierWidget =
        getSupplierWidget(request);
    if (supplierWidget.isPresent()) {
        return supplierWidget;
    }
    return Optional.empty;
}
 
// imagine the subsidiary functions

Таким образом, это лучше, чем null , так как возвращаемое значение not found, и старается изо всех сил использовать подпрограммы, чтобы эта функция описывала себя, но возникает проблема с тем фактом, что каждый из возвращаемых Optional объектов не может быть связан в цепь ответственности.

Мы могли бы обмануть:

01
02
03
04
05
06
07
08
09
10
11
12
13
Optional<Widget> shelfWidget = getShelfWidget(request);
Optional<Widget> backroomWidget = getBackroomWidget(request);
Optional<Widget> supplierWidget = getSupplierWidget(request);
 
return firstNonEmpty(shelfWidget, backroomWidget, supplierWidget);
 
private static Optional<Widget> firstNonEmpty(
            Optional<Widget> ... options) {
    return Arrays.stream(options)
        .filter(Optional::isPresent)
        .findFirst() // makes an optional of optional here...
        .orElse(Optional.empty());
}

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

Первое прошлое сообщение с дополнительным решением

Передайте поток или массив varargs в функцию, состоящую из объектов, которые предоставят необязательный. Если кто-то из них поставляет непустой, он побеждает.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
// calling code
public Optional<Widget> getAppropriateWidget(CustomerRequest request) {
    return firstAvailable(() -> getShelfWidget(request),
        () -> getBackroomWidget(request),
        () -> getSupplierWidget(request));
}
 
// this is a general purpose solution
// feel free to use it
@SafeVarargs
private static <T> Optional<T> firstAvailable(
        Supplier<Optional<T>> ... options) {
    return Arrays.stream(options)
            .map(Supplier::get)
            .filter(Optional::isPresent)
            .findFirst()
            .orElse(Optional.empty());
}

Смотрите оригинальную статью здесь: First Past the Post

Мнения, высказанные участниками Java Code Geeks, являются их собственными.