Ответ 1
У вас есть 3 решения.
Решение 1
Во-первых, вы можете сделать ваши классы обобщенными, например:
public abstract class Contact<E extends Event> {
// ...
public abstract Set<E> getEventsWithinPeriod(DateTime start, DateTime end);
}
И затем в вашей конкретной реализации:
public class PersonalContact extends Contact<Birthday> {
public Set<Birthday> getEventsWithinPeriod(DateTime start, DateTime end) { ... }
}
Это лучшее решение, но у вас есть альтернативы.
Решение 2
Вы можете изменить тип поля birthdaysThatAreWithin
:
Set<Event> birthdaysThatAreWithin = new TreeSet<Event>();
а также изменить подпись метода:
public Set<Event> getEventsWithinPeriod(DateTime start, DateTime end) {
и вернуть его так. Это ограничивает вас, потому что вы больше не можете использовать события как Birthday
.
Решение 3
Вы также можете изменить свою подпись метода (как в своем абстрактном, так и в конкретном классе):
public Set<? extends Event> getEventsWithinPeriod(DateTime start, DateTime end)
и ничего не измените. Это имеет ту же проблему, что и решение 2, вы не сможете использовать события как Birthday
экземпляры без их литья.
Изменить: нижние стороны до 2 и 3 - это то, что они потребуют кастинга. Например:
PersonalContact contact = ... ;
Set<Event> events = personalContact.getEventsWithinPeriod(start, end);
// I know all the events are birthdays, but I still have to do this:
for (Event event : events) {
if (event instanceof Birthday) {
Birthday birthday = (Birthday) event;
// Do stuff with birthday
} // else maybe log some error or something
}
При первом решении вы получите следующее:
PersonalContact contact = ... ;
Set<Birthday> birthdays = personalContact.getEventsWithinPeriod(start, end);
for (Birthday birthday : birthdays) {
// Do stuff with birthday
}
Код выглядит более чистым и работает лучше, потому что вам не нужно делать instanceof
проверки, чтобы убедиться, что вы не получаете ClassCastException
. У вас также могут быть такие вещи:
public static void processBirthdaysFor(Contact<Birthday> birthdayContact, DateTime start, DateTime end) {
Set<Birthday> birthdays = personalContact.getEventsWithinPeriod(start, end);
for (Birthday birthday : birthdays) {
// Do stuff with birthday
}
}
И если у вас есть еще одна реализация Contact
с событиями Birthday
, вы можете передать их этому методу processBirthdaysFor
без внесения каких-либо изменений.
Однако, если вам нужны только события, и вам все равно, какие типы находятся в коде, вызывающем ваш Contact.getEventsWithinPeriod
, тогда решения 2 и 3, безусловно, ваши лучшие ставки. Я бы просто использовал решение 2, если бы это было так.