2012-11-02 36 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

相關問題