#java #oop #inheritance #immutability
Вопрос:
У меня есть базовый класс и производный класс, оба предназначены для неизменяемости (ctor и геттеры опущены).:
public class PageQuery<T> {
private final T queryFilter;
private PageCond pageCond; // pagination parameter
// E withPageCond(PageCond newPageCond) {
// return a brand new copy of `this` with `pageCond` replaced with `newPageCond`
// that can be reused across class hierarchy
// }
}
public class PageSortQuery<T> extends PageQuery<T>{
private final SortCond sortCond; // sorting parameter
}
Как добавить метод, возвращающий защитную копию this
в базовый класс, чтобы все классы в этой иерархии могли извлечь из этого выгоду? Есть ли способ сделать это без clone()
этого ?
Комментарии:
1. Можете ли вы определить защищенные поля и получить к ним доступ из подклассов?
2. @Барракуда, может быть. Но моя цель состоит в том, чтобы все классы были дополнительно добавлены в эту иерархию, чтобы извлекать выгоду
withPageCond
прозрачно с минимальными усилиями. Добавление кода в каждый подкласс не является разумным вариантом для моей цели.3. Шаблон дизайна Builder — хорошая потенциальная замена вашему дизайну. Здесь
PageQuery<T>
невозможно предвидеть, как он будет получен, поэтому он не может контролировать создание экземпляров объектов из несуществующих подклассов.4. @CedricSun, в каком смысле вы хотите, чтобы другие подклассы извлекли из этого выгоду? Есть ли какие-либо проблемы с определением метода копирования в суперклассе, который возвращает копию неизменяемого экземпляра и переопределяет этот метод в подклассах, поскольку они имеют доступ к полю своего суперкласса через методы получения?
5. Подклассы @Barracuda даже не должны знать о наличии
PageCond
поля. Все , что они знают, — это унаследованный методwithPageCond
, вызов которого вернет копиюthis
(с согласованным типом-типом вызывающего подкласса). Не нужно ничего отменять.
Ответ №1:
Я не знаю, имеете ли вы в виду что-то подобное, в этом случае, если вы вызовете метод withFilter, происхождение не изменится.
@AllArgsConstructor
public class Query <T> {
@Getter
private final String name;
@Getter
private final Predicate<T> filter;
public Query<T> withFilter(Predicate<T> filter){
return new DelegatingQuery<T>(this){
@Override
public Predicate<T> getFilter() {
return Query.this.filter;
}
};
}
static class DelegatingQuery<T> extends Query<T>{
@Delegate
private final Query<T> query;
public DelegatingQuery(Query<T> query) {
super(query.name,query.filter);
this.query = query;
}
}
}
Комментарии:
1. Мне нравится, как это осталось
filter
окончательным, но смысл в том, чтобы один или несколько подклассов добавляли бизнес-поля в базуQuery
и использовали один и тот жеwithXXX()
метод (типобезопасным способом).2. Вы хотите, чтобы метод withXXX() возвращал экземпляр подкласса?
3. ДА. Я думаю о CRTP , как о
java.lang.Enum
том, чтобы базовый класс мог ссылаться на тип своего подкласса. Но это привело бы к 3-уровневому наследованию, поскольку должен быть абстрактный базовый класс, а CRTP с многоуровневым (более 2) наследованием всегда является проблемой (возможно, но там много усилий)… не говоря уже о расходах на техническое обслуживание. Также я не могу избежатьclone
этого до сих пор.