2013-08-13 13 views
7

Ich versuche, einige benutzerdefinierten Ausnahmen mit Hilfsmethoden zu schreiben für die Variablen wie diese Einstellung:Java Abstrakte Klassen: Zurückgeben „dieser“ Zeiger für abgeleitete Klassen

public class KeyException extends RuntimeException { 
    protected String Id; 

    protected KeyException(String message) { 
     super(message); 
    } 

    protected KeyException(String message, Throwable cause) { 
     super(message, cause); 
    } 

    public String getId() { 
     return keyId; 
    } 

    public KeyException withId(final String Id) { 
     this.Id = Id; 
     return this; 
    } 
} 

Doch meine abgeleiteten Klassen, ich nicht verwenden kann, die "withId" -Methode, da sie nur die Basisklasse zurückgibt - gibt es trotzdem den "this" -Zeiger zurück, ohne die Methode in jeder einzelnen abgeleiteten Klasse zu überschreiben?

+1

'this' bezieht sich auf das aktuelle Objekt, daher ist es der Typ einer Derived-Klasse, wenn Sie ein abgeleitetes Objekt verwenden. – midhunhk

+0

@silverback Dies ändert nicht den Rückgabetyp, so dass der Compiler nicht weiß, dass der Typ "Derived" ist. –

+0

Ich habe es so belassen, aber wenn ich eine Instanz eines abgeleiteten Typs erstelle, gibt es immer den Basistyp zurück Ich bin nicht in der Lage, die Methoden – KingTravisG

Antwort

8
(wie ich einen formellen Vorschlag vorgeschlagen glauben)

Gibt es sowieso den "This" -Zeiger zurückgeben, ohne die Methode in jeder einzelnen abgeleiteten Klasse zu überschreiben?

Ja, schauen Sie sich die Option 1 unten an.

Es gibt mehrere Möglichkeiten, wie Sie hier tun können:

  1. Guss das Ergebnis der abgeleiteten Klasse

  2. außer Kraft setzen es in Subklassen

  3. ändern Rückgabetyp void. Da Sie eine Methode für ein Objekt aufrufen, haben Sie bereits einen Zeiger darauf.

+0

Ging mit dieser Option, obwohl es ein bisschen mehr Mühe war es erreicht, was ich tun wollte, das scheint unmöglich zu sein, wie ich es wollte! – KingTravisG

-1

leider nicht. Es wäre gut, wenn man diese

public this withId(final String Id) { // doesn't work 
    this.Id = Id; 
    return this; 
} 

oder nur

public this withId(final String Id) { // doesn't work either 
    this.Id = Id; 
} 

oder es würde wissen, dass „Leere“ Methoden implizit verkettet sind, tun könnte

7

Sie können etwas tun:

public <T extends KeyException> T withId(final String Id) { 
    this.Id = Id; 
    return (T)this; 
} 

Dann in der abgeleiteten Klasse, die Sie gerade seinen Typ als Typ-Parameter übergeben.

Es kann jedoch eine Designüberwachung geben. Abgesehen vom Builder-Muster sehe ich selten, dass Setter einen Verweis auf das Objekt selbst zurückgeben. Wenn Sie mehr Kontext bereitstellen würden, wären wir in der Lage, Ihnen mehr zu helfen.

+1

Abgesehen von dem Builder-Muster haben Sie alle anderen Implementierungen der [Fluent-Schnittstelle] (https://en.wikipedia.org/wiki/Fluent_interface) :-) –

0

Es gibt einen Weg, um die Rückkehr Unterklasse Problem mit Generika zu lösen:

// base class 

public class Base<T extends Base> { 

    private T myself; 

    public Base(T myself, Class<T> cls) { 
    this.myself = myself; 
    } 

    public T withSomething() { 
    return myself; 
    } 
} 

// subclass 

public class SomeSubCls extends Base<SomeSubCls> { 

    public SomeSubCls() { 
    super(this, SomeSubCls.class); 
    } 
} 

Mit diesem Muster new SomeSubCls().withSomething() wird das Objekt als Instanz der Unterklasse zurückgeben, anstatt die Eltern.

Wird von fest assertions zum Beispiel überprüfen this

+0

Das wird nicht mit abgeleiteten Klassen von "Throwable" –

+0

funktionieren Stimmt, mein Schlechter. 'Eine generische Klasse erweitert möglicherweise java.lang.Throwable' nicht. – nre

+0

Bitte bearbeiten Sie Ihre Antwort, damit ich den Downvote entfernen kann. –

1

Wenn Sie eine abgeleitete Klasse, z.B.

public class AnotherException extends KeyException { 
    ... 
} 

.... dann können Sie es withId mit asign simpy ....

AnotherException a = new AnotherException ("A"); 
AnotherException b = (AnotherException) a.withId("ID"); 

... weil es im Grunde das gleiche Objekt ist. Sie müssen es nur umsetzen.

2

Es ist möglich, mit Generika mit dem folgenden Konstrukt:

public class ParentType<T extends ParentType<T>> { 
    public T withId(String someId) { 
     /* Insert other code here */ 
     return (T) this; 
    } 
} 

public class BranchType<T extends BranchType<T>> extends ParentType<T> {} 

public final class LeafTypeA extends BranchType<LeafTypeA> {} 

public final class LeafTypeB extends ParentType<LeafTypeB> {} 

Wo BranchType eine Klasse mit Unterklassen ist und LeafTypeA, LeafTypeB sind Klassen ohne Unterklassen.

Dies ist eine leichte Verbesserung gegenüber der anderen Generika Lösung, da es verhindert:

public class LeafTypeA extends BranchType<LeafTypeB> {} 

Da dies nicht die Einschränkungen des Typs Parameter erfüllen.

Verwandte Themen