Java — два почти одинаковых метода с разным типом возврата

Интересно, как я могу избежать дублирования кода в моем примере ниже. У меня есть два метода, где один из параметров немного отличается и возвращается немного другой объект (один из них - простой - имеет меньше полей объекта)

public class WarehouseSimpleSearchFilter {
    long companyId;
    private Set<Long> shipperIds;
    private Set<Long> carrierIds;
}
public class WarehouseSearchFilter extends WarehouseSimpleSearchFilter {
    long companyId;
    private String search;
    private Boolean isLocked;
}
private WarehouseSimpleSearchFilter getWarehouseSimpleSearchFilter(Set<Long> carrierIds, Set<Long> shipperIds, Authorization authorization, WarehouseSimpleSearchFilter searchFilter) {
        if (CollectionUtils.isEmpty(carrierIds) && CollectionUtils.isEmpty(shipperIds)) {
            final Set<Long> newCarrierIds = getCompanyId(WarehousePermission.READ_AVAILABLE, authorization);
            final Set<Long> newShipperIds = getCompanyIds(WarehousePermission.READ_COMPANY, authorization);
            searchFilter.setCarrierIds(newCarrierIds);
            searchFilter.setShipperIds(newShipperIds);
            return searchFilter;
        }
        if (!CollectionUtils.isEmpty(carrierIds)) {
            checkPermission(WarehousePermission.READ_AVAILABLE, authorization);
            searchFilter.setCarrierIds(Collections.unmodifiableSet(carrierIds));
        }
        if (!CollectionUtils.isEmpty(shipperIds)) {
            checkPermission(WarehousePermission.READ_COMPANY, authorization);
            searchFilter.setShipperIds(Collections.unmodifiableSet(shipperIds));
        }
        return searchFilter;
    }

    private WarehouseSearchFilter getWarehouseSearchFilter(Set<Long> carrierIds, Set<Long> shipperIds, Authorization authorization, WarehouseSearchFilter searchFilter) {
        if (CollectionUtils.isEmpty(carrierIds) && CollectionUtils.isEmpty(shipperIds)) {
            final Set<Long> newCarrierIds = getCompanyIds(WarehousePermission.READ_AVAILABLE, authorization);
            final Set<Long> newShipperIds = getCompanyIds(WarehousePermission.READ_COMPANY, authorization);
            searchFilter.setCarrierIds(newCarrierIds);
            searchFilter.setShipperIds(newShipperIds);
            return searchFilter;
        }
        if (!CollectionUtils.isEmpty(carrierIds)) {
            checkPermission(WarehousePermission.READ_AVAILABLE, authorization);
            searchFilter.setCarrierIds(Collections.unmodifiableSet(carrierIds));
        }
        if (!CollectionUtils.isEmpty(shipperIds)) {
            checkPermission(WarehousePermission.READ_COMPANY, authorization);
            searchFilter.setShipperIds(Collections.unmodifiableSet(shipperIds));
        }
        return searchFilter;
    }
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, что эти методы идентичны, но один из них работает с подклассом. Вы можете использовать дженерики, чтобы написать их за один раз.

private <T extends WarehouseSimpleSearchFilter> T getWarehouseSimpleSearchFilter(
  Set<Long> carrierIds,
  Set<Long> shipperIds,
  Authorization authorization,
  T searchFilter
) {
  ...
}

Однако здесь есть несколько вещей, на которые следует обратить внимание.

Во-первых, похоже, что вы всегда просто изменяете аргумент searchFilter и возвращаете его. Если это так, вы можете просто вернуть void и взять WarehouseSimpleSearchFilter в качестве аргумента. Нет смысла возвращать то же самое значение, которое вы передали, если только вы не разрабатываете свободный интерфейс (и рассматриваемый аргумент не является получателем в вашем примере, так что это здесь не применимо).

Во-вторых, я оспариваю использование здесь наследования. У вас есть родительский класс, который кажется «простым» поисковым фильтром, а затем вы создаете его подкласс для расширения функциональности. Это классический антипаттерн, который раньше преподавали в школах, и ваш «простой» поисковый фильтр, скорее всего, станет хрупким базовым классом. Наследование должно моделировать отношение «есть-а». И хотя я не вижу, какие методы доступны в вашем поисковом фильтре, само соглашение об именах подсказывает мне, что «расширенный» поисковый фильтр на самом деле не является простым поисковым фильтром. Похоже, вы используете наследование как инструмент удобства реализации, а не для правильного моделирования объектного пространства.

Вместо этого я бы предложил иметь интерфейс, представляющий абстрактный API, поддерживающий как простые, так и расширенные поисковые фильтры. Если между ними есть значительная общая функциональность, которая не зависит от какого-либо конкретного состояния класса, то ее можно где-то выделить в статические методы или методы по умолчанию в самом интерфейсе. Тогда каждая из ваших реализаций фильтра поиска может быть реализатором этого интерфейса, а ваша универсальная функция может принимать интерфейс (или ограниченный универсальный интерфейс, как указано выше) в качестве аргумента.

У меня есть 2 типа возврата, потому что у меня есть 2 немного разные конечные точки, которые должны возвращать полные данные и ограниченные данные (simpleDto). Итак, могу ли я по-прежнему использовать наследование, как в моем примере?

Matley 06.04.2023 16:25

Другие вопросы по теме