각 도메인 로직을 조합하여 Application 로직을 만들다 보면 아래와 같은 코드가 많이 보인다.
•
스토어와 상품을 찾아 스토어에서 해당 상품을 삭제 하는 로직
@Transactional
public void deleteProduct(final Long storeId,final Long productId) {
// 스토어를 찾는다.
final Store foundStore = storeService.findStoreById(storeId)
.orElseThrow(StoreNotFoundException::new);
// 상품을 찾는다.
final Product product = productService.findProductById(productId)
.orElseThrow(() -> new BusinessException(ErrorCode.PRODUCT_NAME_IS_EMPTY));
// 스토어에서 상품을 지운다.
foundStore.deleteProduct(product);
}
Java
복사
위 처럼 두 가지 모두 존재해야 실행할 수 있는 특정 상황에 사용할 수 있는 메서드가 있다.
public interface Optionals {
public static boolean isAnyPresent(Optional<?>... optionals) {
Assert.notNull(optionals, "Optionals must not be null");
return Arrays.stream(optionals).anyMatch(Optional::isPresent);
}
public static <T, S> void ifAllPresent(Optional<T> left, Optional<S> right, BiConsumer<T, S> consumer) {
Assert.notNull(left, "Optional must not be null");
Assert.notNull(right, "Optional must not be null");
Assert.notNull(consumer, "Consumer must not be null");
mapIfAllPresent(left, right, (l, r) -> {
consumer.accept(l, r);
return null;
});
}
public static <T, S, R> Optional<R> mapIfAllPresent(Optional<T> left, Optional<S> right,
BiFunction<T, S, R> function) {
Assert.notNull(left, "Optional must not be null");
Assert.notNull(right, "Optional must not be null");
Assert.notNull(function, "BiFunction must not be null");
return left.flatMap(l -> right.map(r -> function.apply(l, r)));
}
}
Java
복사
Optionals 인터페이스에서 Optional을 조합하여 로직을 실행하는 메서드를 정적 메서드로 제공하고 있다.
ifAllPresent
Optional<T>, Optional<S> 타입의 매개변수를 받고 두 매개변수를 받아 처리하는 BiConsumer<T,S>도 받는다.
여기서 BiConsumer의 제너릭 타입은 ifAllPresent 메서드에서 첫번째와 두번 째 받은 Optional 타입의 제너릭 타입과 같은 타입이다.
다시 말해 매개변수로 받은 Optional 타입의 값 두개가 모두 존재한다면 BiConsumer를 실행한다.
1.
값 검증
Assert.notNull(left, "Optional must not be null");
Assert.notNull(right, "Optional must not be null");
Java
복사
2.
BiConsumer 실행
return left.flatMap(l -> right.map(r -> function.apply(l, r)));
Java
복사
존재 여부가 불확실한 두 변수가 둘다 존재할 때만 특정 로직을 실행하는 상황에서 이 메서드를 사용하면 간단한 처리가 가능하다.
// Store, Category 두개 다 존재하는 상황에서 카테고리를 삭제한다.
return mapIfAllPresent(
of(foundStore),
categoryService.findCategory(foundStore, categoryName),
Store::deleteCategory)
.map(StoreResponse::from)
.orElseThrow(NoSuchElementException::new);
}
Java
복사
만약 리턴 값을 통해 다른 타입으로 매핑하는 상황이 아니라면 리턴 값이 필요없는 ifAllPresent() 메서드를 사용해도 좋다.