2012-11-02 4 views
11

Ich baue einen "Kontaktmanager" in Java.Definieren einer generischen Methode für zwei Unterklassen, die dieselbe Schnittstelle implementieren

Ich habe eine übergeordnete Klasse namens "Kontakt, die zwei Basisklassen hat;. PersonalContact und BusinessContact

Ich habe eine Schnittstelle Ereignis genannt, die von Klassen implementiert wird Geburtstag und Meeting. (Birthday enthält ein DateTime-Objekt, während Meeting zwei für die Start- und Endzeit hat.)

PersonalContact hält eine TreeSet von Geburtstage und BusinessContact hält einen Satz von Meetings.

nun in der übergeordneten Klasse Kontakt, ich möchte eine abstrakte Methode namens „getEventsWithinPeriod()“, die eine TreeSet aller Geburtstage und/oder Sitzungen innerhalb einer bestimmten Zeitspanne zurück.

Das Problem ist, ich weiß nicht, wie die abstrakte Methode zu sagen, und dann die Basisklasse Methoden, was zurückgeben.

Zum Beispiel ist dies der Code, den ich in Kontakt;

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

Und in PersonalContact;

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

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

jedoch im Compiler, erhalte ich einen Fehler auf Set<Birthday> sagen;

„Der Rückgabetyp ist unvereinbar mit Contact.getEventsWithinPeriod (Datetime, Datetime)“

Was sind die richtigen Begriffe und kehrt ich verwenden sollte? Warum ist mein aktueller Versuch falsch?

+2

Warum möchten Sie nicht weiter 'Event' Schnittstelle verwenden? Die Hauptidee der Schnittstelle, um Code klar zu machen, indem man Liste der sichtbaren Methode für die Implementierung definiert.Verwenden Sie einfach 'TreeSet ' –

+0

Ich bin in völliger Übereinstimmung, @ Fess - es scheint nur klar, dass "getEvents ..." Ereignisse zurückgibt, nicht wahr? Der Einsatz von Generika ist in diesem Fall einfach verwirrend und wenig hilfreich. –

+0

Ja, ihr habt recht, ich habe es so gemacht. Ich hatte kein klares Verständnis davon, wie die Schnittstelle dazu verwendet werden könnte, beide Klassen unter dem Banner "Events" als denselben Typ zu vereinen. Danke für Ihre Hilfe! – CodyBugstein

Antwort

6

Sie haben 3 Lösungen.

Lösung 1

Erstens können Sie Ihre Klassen generic machen, etwa so:

public abstract class Contact<E extends Event> { 
    // ... 

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

Und dann in der konkreten Umsetzung:

public class PersonalContact extends Contact<Birthday> { 

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

Dies ist die beste Lösung , aber Sie haben einige Alternativen.

Lösung 2

Sie die Art Ihrer birthdaysThatAreWithin Feld ändern können:

Set<Event> birthdaysThatAreWithin = new TreeSet<Event>(); 

sowie die Methodensignatur ändern:

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

und senden Sie es so. Dies schränkt Sie ein, da Sie die Ereignisse nicht mehr als Birthday Instanzen verwenden können.

Lösung 3

Sie könnten Ihre Methodensignatur ändern auch (in beide Ihre abstrakten und konkreten Klasse) dazu:

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

und nichts anderes ändern. Dies hat das gleiche Problem wie Lösung 2, Sie können die Ereignisse nicht als Birthday Instanzen verwenden, ohne sie zu übertragen.

Bearbeiten: die Schattenseiten zu 2 und 3 sind, dass sie Gießen erfordern. Zum Beispiel:

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 
} 

Mit der ersten Lösung, dann würden Sie dieses:

PersonalContact contact = ... ; 
Set<Birthday> birthdays = personalContact.getEventsWithinPeriod(start, end); 
for (Birthday birthday : birthdays) { 
    // Do stuff with birthday 
} 

Der Code sieht sauberer und läuft besser, weil Sie nicht instanceof Kontrollen tun müssen, um sicherzustellen, dass Sie don Erhalten Sie keine ClassCastException. Sie können auch Sachen wie diese haben:

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

Und wenn Sie jemals eine andere Implementierung von Contact haben, die Birthday Ereignisse hat, können Sie sie zu diesem processBirthdaysFor-Methode übergeben, ohne Änderungen vorzunehmen.

jedoch, wenn Sie nur die Ereignisse brauchen, und Sie es egal, was die Typen im Code aufrufen Ihre Contact.getEventsWithinPeriod, dann Lösungen 2 und 3 sind definitiv Ihre besten Wetten. Ich würde persönlich Lösung 2 verwenden, wenn dies die Situation wäre.

+0

Danke, ich denke Lösung 2 wird großartig sein. Meine Frage ist jedoch, was ist der Nachteil? Was bedeutet es, dass ich die Ereignisse nicht als Geburtstagsinstanzen verwenden kann? Was verliere ich? – CodyBugstein

+1

@Imray Ich werde meine Antwort aktualisieren – Brian

+1

@Imray Antwort aktualisiert, werfen Sie einen Blick. – Brian

10

Sie benötigen 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

Ich weiß nicht, ob '' gute Praxis ist. Weil "T" alles sein sollte, ist es wie eine Standardschnittstelle. vielleicht 'Kontakt ' –

+0

@Fess Es ist bereits aktualisiert. Bitte überprüfen Sie –

+0

Oh, gut, danke –

0

Methode Signatur verwenden, sollte gleich bleiben, während jede Methode überschreiben, sollten Sie Unterschrift gleich bleiben und

0

in PersonalContact Klasse Set zurück, wenn die Verwendung von Generika, Sie don‘ t möchte den Typ explizit angeben. Sie können den Typ begrenzen, aber Sie möchten nicht explizit sein.

Ihre Contact Methode ändern zu

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

und PersonalContact zu

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

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

ändern, dass Sie sollten bekommen, was Sie wollen.

+0

Muss ich die Kontaktklasse nicht in Contact ändern? – CodyBugstein

Verwandte Themen