2016-05-04 4 views
4

Also habe ich ein paar vererbte Klassen wie so definiert.Java-Polymorphie und Methodenverkettung

class Base { 
    public Base chainedMethodA() { 
     // some stuff 
     return this; 
    } 
} 

class Derived extends Base { 
    public Derived chainedMethodB() { 
     // some stuff 
     return this; 
    } 
} 

Nun wird der folgende Code funktioniert:

Derived obj = new Derived(); 
obj.chainedMethodB().chainedMethodA(); 

Aber dies nicht (man beachte die geänderte Reihenfolge der Funktionsaufrufe):

Derived obj = new Derived(); 
obj.chainedMethodA().chainedMethodB(); 

Der Compiler gibt einen Fehler auf dem chainedMethodB() Funktionsaufruf Ich kann verstehen, dass dies daran liegt, dass beim Ausführen von ein Objekt vom Typ Base zurückgegeben wird, für das chainedMethodB nicht definiert ist.

Ich kann für dieses Problem von wenigen Lösungen denken:

  1. Ketten Methoden während Aufmerksamkeit (nennen wir Derived ‚s Methoden zuerst, und dann rufen Base‘ s Methoden) auf Bestellung. Das sieht nach einer sehr spröden Lösung aus.
  2. Überschreiben chainedMethodA in Derived, so dass es eine Instanz Derived anstelle von Base zurückgibt. Das sieht nach einer Verschwendung von Erbschaft aus.

Gibt es einen eleganten Weg um dieses Problem? Vielleicht ein Konstrukt, das auf magische Weise chainedMethodA ändert, um eine Derived Instanz zurückzugeben, wenn es von einem Objekt des Typs Derived aufgerufen wird, ohne explizit in Derived überschrieben zu werden.

+5

2 nicht eine Verschwendung von Vererbung ist. Es ist, was Vererbung ist: override, um etwas spezifischer zu tun, in diesem Fall: einen spezifischeren Typ zurückgeben. – Tunaki

+1

@TI Sicher wird es: Sie können überschreiben und erklären, einen spezifischeren Typ zurückzugeben. Mit '@Override public Abgeleitetes chainedMethodA() {...}' – Tunaki

+0

Beachten Sie, dass, wenn Sie wollen, dass 'Derived's' chainedMethodA' eine Instanz von 'Derived' zurückgibt, die Superimplementierung trotzdem nicht aufrufen kann (weil das eine tatsächliche 'Basis' zurückgeben könnte, die nicht 'abgeleitet' ist). Du verlierst also nichts auf diese Weise und erlaubst dir, dass "abgeleitete" Objekte immer noch als Basis verwendet werden. –

Antwort

2

Aufschalten chainedMethodA in Derived so gibt es eine Instanz von Derived statt Base. Das sieht nach einer Verschwendung von Erbschaft aus.

Sie liegen falsch. Sie verschwenden keine Erbschaft.

Technik des Überschreibens ist genau das zu tun, nämlich eine Methode zu spezialisieren. Das Überschreiben kann ausgeführt werden, wenn der zurückgegebene Typ identisch ist oder ein Untertyp des Rückgabetyps, der in der ursprünglichen überschriebenen Methode in der Oberklasse deklariert wurde. In diesem Fall verletzen Sie also nichts.

Lesen Sie here für mehr über das Überschreiben.

Hier Beispiel 1: (die übergeordnete Klasse Methode aufrufen)

public class Derived extends Base { 
    @Override 
    public Derived chainedMethodA(){ 

     super.chainedMethodA(); 
     //some stuff 
     return this; 
    } 

    public Derived chainedMethodB() { 
     // some stuff 
     return this; 
    } 
} 

Hier Beispiel 2: (Ändern es completele)

public class Derived extends Base { 
    @Override 
    public Derived chainedMethodA(){ 
     //some stuff 
     return this; 
    } 

    public Derived chainedMethodB() { 
     // some stuff 
     return this; 
    } 
    } 
+1

IMO, könnte Ihre Antwort von einem Beispiel für solche übersteuern :). – Tunaki

+0

@Tunaki du hast Recht – granmirupa

+0

Danke für die Bearbeitung! Ich bin mir nicht so sicher über 'return (Derived) super.chainedMethodA();'. 'chainedMethodA' könnte eine' Base' zurückgeben und dies würde fehlschlagen ('ClassCastException'). Wie wäre es mit 'super.chainedMethodA(); gib das zurück; '? – Tunaki

0

In dieser Situation Vererbung ist wahrscheinlich die einfachste Lösung.

jedoch Ihr letzter Satz erklärt ziemlich Generika:

Vielleicht ein Konstrukt, das chainedMethodA magisch ändert eine abgeleitete Instanz, wenn sie durch ein Objekt vom Typ abgeleitet, ohne wird ausdrücklich außer Kraft gesetzt in Derived aufgerufen zurückzukehren.

So etwas wie dies auch in anderen ähnlichen Anwendungsfällen nützlich sein:

static class Base { 
    public <T extends Base> T chainedMethodA(Class<T> clazz) throws Exception { 
     // some stuff 
     return clazz.cast(this); 
    } 
} 

static class Derived extends Base { 
    public Derived chainedMethodB() { 
     // some stuff 
     return this; 
    } 
} 

public static void main(String args[]) throws Exception { 
    Derived obj = new Derived(); 
    obj.chainedMethodA(Derived.class).chainedMethodB(); 
} 
+1

Nein. Das ist Overkill. Glauben Sie wirklich, dass die Einführung der Reflection API hier unbedingt erforderlich ist? Außerdem macht es nicht, was das OP will, da es eine neue Instanz erstellt. – Tunaki

+0

OP war mehr besorgt über Rückgabetypen, so dass ich nicht darauf geachtet habe, was die Methode tatsächlich macht. Trotzdem habe ich aktualisiert, so dass es die gleiche Instanz zurückgibt. (und ich stimme zu, es ist wahrscheinlich Overkill in der OP-Situation, daher die erste Zeile) – cowls