Часто мы пишем код, чтобы выработать первый ответ из множества доступных. Давайте посмотрим на это в 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, являются их собственными. |