2012-11-02 37 views
11

我正在用Java构建“联系人管理器”。定义实现相同接口的两个子类的通用方法

我有一个名为“联系其具有两个基类的超类。PersonalContactBusinessContact

我有称为事件的接口,它是由类生日实施会议。(生日包含一个DateTime对象,而Meeting有两个开始和结束时间)。

PersonalContact拥有TreeSet 生日BusinessContact拥有一组会议。

如今,在超联系,我想创建一个名为“getEventsWithinPeriod()”,将在给定的时间跨度内返回所有生日和/或会议的一个TreeSet抽象方法。

问题是,我不知道如何告诉抽象方法,然后基类方法返回什么。

例如,这是我在中使用的代码联系人;

public abstract Set<Event> getEventsWithinPeriod(DateTime start, DateTime end);

而且在PersonalContact;

public Set<Birthday> getEventsWithinPeriod(DateTime start, DateTime end){ 

     Set<Birthday> birthdaysThatAreWithin = new TreeSet<Birthday>(); 
     //CODE 
     return birthdaysThatAreWithin; 

然而,在编译器,我就Set<Birthday>说得到一个错误;

“的返回类型是Contact.getEventsWithinPeriod(日期时间,日期)不兼容的”

什么是适当的条款和回报,我应该使用?为什么我目前的尝试错误?

+2

为什么你不想继续使用'Event'接口?接口的主要思想是通过定义实现的可见方法列表来使代码清晰。只需使用'TreeSet ' –

+0

我完全同意@Fess - 这似乎很清楚,“getEvents ...”返回事件,不是吗?在这种情况下使用泛型只是混淆和无益的。 –

+0

是的,你们是对的,我最终这样做了。我没有清楚地了解如何使用界面将两个班级统一为“Events”标题下的相同类型。谢谢你的帮助! – CodyBugstein

回答

6

您有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 
    } 
} 

如果你曾经有ContactBirthday事件另一种实现方式,可以将它们传递给processBirthdaysFor方法,无需进行任何更改。

然而,如果你只需要事件和你不在乎什么类型的代码中调用你的Contact.getEventsWithinPeriod,然后解决方案2和3是绝对你最好的赌注。如果是这种情况,我个人只会使用解决方案2。

+0

谢谢,我认为解决方案2将会很棒。我的问题是,实际上缺点是什么?这意味着我将无法将这些事件用作生日实例?我输了什么? – CodyBugstein

+1

@Imray我会更新我的答案 – Brian

+1

@Imray回答更新,看看。 – Brian

10

您需要使用generic Types

public abstract class Contact<T extends Event> { 
    public abstract Set<T> getEventsWithinPeriod(Date start, Date end); 
} 
public class BirthDay extends Contact<BirthDay> implements Event { 

    @Override 
    public Set<BirthDay> getEventsWithinPeriod(Date start, Date end) { 
     return null; 
    } 
} 
+0

我不知道''是不是很好的做法。因为'T'应该是一切,就像它的默认界面一样。也许'联系' –

+0

@Fess它已经更新。请检查 –

+0

噢,很好,谢谢 –

0

方法签名应该保持不变,而覆盖的任何方法,你的签名应该保持相同,返回位于PersonalContact类

0

当使用泛型,你不”你想明确指定类型。你可以绑定这个类型,但你不想明确。

Contact方法更改为

public abstract Set<T extends Event> getEventsWithinPeriod(DateTime start, DateTime end); 

,改变PersonalContact

public Set<T extends Event> getEventsWithinPeriod(DateTime start, DateTime end){ 

     Set<T> birthdaysThatAreWithin = new TreeSet<Birthday>(); 
     //CODE 
     return birthdaysThatAreWithin; 
} 

应该得到你想要的东西。

+0

不需要将联系人类更改为联系然后? – CodyBugstein

相关问题