15. Реализовать стратегию фильтрации заказов с помощью лямбд
Условие задачи:
Дан класс Order с полями:
price— стоимость заказа;date— дата заказа;status— статус заказа.
Необходимо реализовать универсальную фильтрацию списка заказов по разным критериям:
по цене;
по дате;
по статусу;
по комбинации нескольких условий.
Стратегию фильтрации нужно передавать в виде лямбда-выражения. При добавлении нового критерия метод фильтрации изменяться не должен.
Код:
public class Order {
private final BigDecimal price;
private final LocalDate date;
private final String status;
public Order(BigDecimal price, LocalDate date, String status) {
this.price = price;
this.date = date;
this.status = status;
}
public BigDecimal getPrice() {
return price;
}
public LocalDate getDate() {
return date;
}
public String getStatus() {
return status;
}
}
public class OrderService {
public static List<Order> filterOrders(
List<Order> orders,
Predicate<Order> filterStrategy
) {
// TODO
return null;
}
}
Спойлеры к решению
Подсказки
Predicate<Order> представляет функцию, которая принимает Order и возвращает boolean.💡 Конкретную стратегию можно передать непосредственно лямбда-выражением.
💡 Метод
filterOrders() не должен знать, по какому именно признаку выполняется фильтрация.💡 Несколько условий можно объединять через
Predicate.and() и Predicate.or().Решение
Метод фильтрации принимает Predicate<Order> и применяет его ко всем заказам:
public class OrderService {
public static List<Order> filterOrders(
List<Order> orders,
Predicate<Order> filterStrategy
) {
return orders.stream()
.filter(filterStrategy)
.collect(Collectors.toList());
}
}
Теперь конкретное условие передаётся снаружи.
Фильтрация по цене:
List<Order> expensiveOrders = OrderService.filterOrders(
orders,
order -> order.getPrice()
.compareTo(new BigDecimal("200.00")) > 0
);
Фильтрация по дате:
List<Order> recentOrders = OrderService.filterOrders(
orders,
order -> order.getDate()
.isAfter(LocalDate.of(2023, 1, 15))
);
Фильтрация по статусу:
List<Order> newOrders = OrderService.filterOrders(
orders,
order -> "NEW".equalsIgnoreCase(order.getStatus())
);
Можно также создавать отдельные стратегии и комбинировать их:
Predicate<Order> delivered =
order -> "DELIVERED".equalsIgnoreCase(order.getStatus());
Predicate<Order> afterFebruary =
order -> order.getDate().isAfter(LocalDate.of(2023, 2, 1));
List<Order> result = OrderService.filterOrders(
orders,
delivered.and(afterFebruary)
);
Основной метод:
filterOrders(List<Order> orders, Predicate<Order> filterStrategy)
остаётся неизменным при появлении новых условий. Меняется только передаваемый Predicate<Order>.
Таким образом, лямбда выступает в роли конкретной стратегии, а OrderService работает с общей абстракцией Predicate<Order>.
Временная сложность фильтрации — O(n), дополнительная память — O(k) для результирующего списка из k подходящих заказов.