Интересно, как я могу избежать дублирования кода в моем примере ниже. У меня есть два метода, где один из параметров немного отличается и возвращается немного другой объект (один из них - простой - имеет меньше полей объекта)
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;
}
Похоже, что эти методы идентичны, но один из них работает с подклассом. Вы можете использовать дженерики, чтобы написать их за один раз.
private <T extends WarehouseSimpleSearchFilter> T getWarehouseSimpleSearchFilter(
Set<Long> carrierIds,
Set<Long> shipperIds,
Authorization authorization,
T searchFilter
) {
...
}
Однако здесь есть несколько вещей, на которые следует обратить внимание.
Во-первых, похоже, что вы всегда просто изменяете аргумент searchFilter
и возвращаете его. Если это так, вы можете просто вернуть void
и взять WarehouseSimpleSearchFilter
в качестве аргумента. Нет смысла возвращать то же самое значение, которое вы передали, если только вы не разрабатываете свободный интерфейс (и рассматриваемый аргумент не является получателем в вашем примере, так что это здесь не применимо).
Во-вторых, я оспариваю использование здесь наследования. У вас есть родительский класс, который кажется «простым» поисковым фильтром, а затем вы создаете его подкласс для расширения функциональности. Это классический антипаттерн, который раньше преподавали в школах, и ваш «простой» поисковый фильтр, скорее всего, станет хрупким базовым классом. Наследование должно моделировать отношение «есть-а». И хотя я не вижу, какие методы доступны в вашем поисковом фильтре, само соглашение об именах подсказывает мне, что «расширенный» поисковый фильтр на самом деле не является простым поисковым фильтром. Похоже, вы используете наследование как инструмент удобства реализации, а не для правильного моделирования объектного пространства.
Вместо этого я бы предложил иметь интерфейс, представляющий абстрактный API, поддерживающий как простые, так и расширенные поисковые фильтры. Если между ними есть значительная общая функциональность, которая не зависит от какого-либо конкретного состояния класса, то ее можно где-то выделить в статические методы или методы по умолчанию в самом интерфейсе. Тогда каждая из ваших реализаций фильтра поиска может быть реализатором этого интерфейса, а ваша универсальная функция может принимать интерфейс (или ограниченный универсальный интерфейс, как указано выше) в качестве аргумента.
У меня есть 2 типа возврата, потому что у меня есть 2 немного разные конечные точки, которые должны возвращать полные данные и ограниченные данные (simpleDto). Итак, могу ли я по-прежнему использовать наследование, как в моем примере?