2009-07-16 8 views
2

Ich habe eine Frage zu Technik und Implementierung, anstatt ein Problem zu lösen. Vor kurzem habe ich eine abstrakte Klasse erstellt, nennen wir sie A, die die allgemeinen Verhaltensweisen ihrer Unterklassen definiert.Instanceof und Type-Casting Techniken

Ich verwende diese mehrere Subklassen B, C und D, die dann in einem anderen Verfahren außerhalb der übergeordneten Klasse-Unterklasse Struktur, die in einem Typ A (so in der Lage nimmt übergeben werden konstruieren sind, um alle von B zu handhaben , C und D).

In Java benutze ich instanceof, um den wahren Typ zu erhalten, aber ich muss am realen Typ viel Casting machen, und es sieht wie ein Durcheinander aus. Hat jemand irgendwelche Vorschläge, wie man den Code sauberer machen kann?

Eine Methode, die ich ausprobiert habe, war, eine Instanz des Unterklasse-Typs aus den Parametern der Oberklasse zu rekonstruieren, so dass ich das Objekt mit seinem tatsächlichen Typ behandeln würde, um so die Typumwandlung zu vermeiden. Da jede dieser Unterklassen Singletons sind (ja, sie halten den Zustand), fühle ich mich wohl dabei. Scheint das wie eine miese Sache zu tun?

Dank an jeden, der antwortet, wird es sehr geschätzt!

Bearbeiten: Ich fügte weitere Klarstellung in Kursivschrift hinzu. Vielen Dank.

+0

Hallo, ich habe dein Problem, und es ist ein schwer zu googeln (ich habe Glück, dass ich es gefunden habe). Können Sie nach längerer Erfahrung diese Frage definitiv beantworten? – bigstones

+1

Versuchen Sie, die Methode so oft wie möglich zu überladen, so dass Sie nie den wahren Typ kennen müssen. Solange jede Unterklasse eine gemeinsame Methode mit verschiedenen Implementierungen hat, müssen Sie den wahren Typ nie kennen. Für e.x. Wenn ich die abstrakte Klasse Animal und die Klassen Dog und Cat habe, die Animal erweitern, würde ich statt einer Methode woof() und einer Methode meow() eine Methode makeSound() oder speak() erstellen, die in beiden existiert. – AlbertoPL

Antwort

3

Generika sind dafür gemacht, damit umzugehen.

Betrachten Sie das folgende Beispiel:

public class SuperClass<T extends SuperClass> { 

    public abstract void someMethod(T param); 

} 


public class SubClassA extends SuperClass<SubClassA> { 

    public void someMethod(SubClassA param) {} 
} 

EDIT: Kommentar gegeben, würde ich dann sagen, das ist ein Design-Geruch. Die gesamte andere Klasse benötigt entweder Unterklassen, auf die Bezug genommen werden kann (zu diesem Zeitpunkt kann die gleiche Technik angewendet werden) oder es ist ein anderes Design-Problem involviert. Es ist seltsam, eine Methode für eine Klasse zu haben, die eine Superklasse einer anderen Klasse übernimmt und sich dann um den Subtyp kümmert.

Wenn Sie das brauchen, können Sie dies einfach mit Überladung der Methode erreichen. Betrachte:

public void someMethod(SuperClass param) { 
     if (param instanceof SubClassA) { 
     someMethod((SubClassA) param); 
     } else if (param instanceof SubClassB) { 
     someMethod((SubClassB) param); 
     } 
    } 

    public void someMethod(SubClassA param) {} 

    public void someMethod(SubClassB param) {} 

Aber das hat dich nicht aus der If-Falle rausgeholt. Es hängt davon ab, wie viele es gibt und wie instabil sie sind, um zu sehen, ob sich hier eine schwerere Lösung lohnt.

+0

Die betreffende Methode gehört vollständig zu einer ganz anderen Klasse. Es ist keine Methode, die zur Oberklasse oder einer ihrer Unterklassen gehört. – AlbertoPL

+0

Methode Überladung ist wahrscheinlich, was ich tun muss. – AlbertoPL

3

Ich verstehe nicht, warum Sie sie von der Basisklasse erben, wenn Sie den Typ überprüfen müssen. Abstrakte Klasse/Schnittstelle A definiert eine Reihe von Funktionen, die B, C und D implementieren sollten, und dann sollte die Funktion, die eine Instanz von A übernimmt, nur diese abstrakten Funktionen aufrufen. Wenn Sie eine Funktion aufrufen müssen, die nur B enthält (und daher nicht überschrieben wird), sollte Ihre Funktion eine Instanz von B und nicht von A nehmen.

Oder fehlt mir der Punkt vollständig? Ich hatte heute Morgen kein Koffein.

+0

Der Punkt ist, dass die beiden nur bestimmte Methoden teilen. Es gibt viele andere Methoden und Variablen, die nur innerhalb der Unterklassen existieren, die nicht geteilt werden oder in irgendeiner Weise kompatibel sind. Ich könnte sie in der Oberklasse definieren, aber dann müssten die anderen Klassen diese Variablen als null behalten, was schlecht zu sein scheint. – AlbertoPL

+2

Das hört sich allerdings schlecht an, da du eine Funktion schreibst, die sagt: "Wenn es Typ B ist, tu/hol dir diese B-spezifische Sache. Wenn es C ist, mach/bekomme diese C-spezifische Sache. Ich würde diese in andere aufteilen Funktionen, die B/C/D-spezifisch waren Es scheint, als wäre es eine monolithische Sache, die wahrscheinlich in einzelne Funktionen ausbrechen würde – MattC

+0

Ja, das ist definitiv etwas, das ich in Erwägung ziehe Danke, – AlbertoPL

0

Es klingt wie Sie wollen Besucher Muster.Persönlich bin ich kein großer Fan, aber es funktioniert wie folgt:

class A { abstract void visit(MyVisitor visitor); } 

dies in jeder Unterklasse implementiert werden muss:

class B extends A { 
    public void visit(MyVisitor v) { v.visit(this); } 
} 

So ist die tatsächlichen Besucher verwenden Überlastung wie folgt:

interface MyVisitor { 
    public void visit(B b); 
    public void visit(C c); 
} 

Jetzt können Sie Ihren Besucher implementieren und visit gegen Ihre Instanz von A aufrufen. Dann wird die richtige Callback-Methode aufgerufen:

A a = new B(); 
a.visit(this); 

Unter der Annahme der this Instanz implementiert MyVisitor, dies in einem Rückruf führen auf der visit(B) Methode

0

Wie Yishai sagte, es sieht aus wie ein Design-Geruch. Wenn Sie instanceof-s haben, was das Verhalten Ihrer Methode ändert, gehen Sie einen falschen Weg. Ziehen Sie in Betracht, dieses Verhalten in die Erben der Klasse A zu verschieben.

Darüber hinaus könnten Sie Generika verwenden, um eine Klasse zu parametrisieren. Hier ist ein Codebeispiel

abstract class A<T extends A>{ 
    abstract protected void someMethod(T value); 
} 

class B extends A<B>{ 
    protected void someMethod(B value) { 
    } 
} 

class C extends A<C>{ 
    protected void someMethod(C value) { 
    } 
}