Eine Frage zu Anti-Patterns

* klassische Singletons
Das klassische Singleton Pattern bindet die Zuständigkeit für Verwaltung der Anzahl der Objektinstanzen an die Klasse selbst. D.h. sie ist dafür zuständig, zu kontorllieren, dass es nur 1 Instanz gibt. Das verletzt zunächst erstmal das prinzip des Separation of Concerns. Zum anderen wird sowas schnell unheimlich kompliziert, wenn man mit verschiedenen ClassLoadern arbeitet (1 Singleton ist nämlcih immer nur per Classloader Singleton - d.h. es ist problemlos möglich trotzdem zwei Instanzen der Klasse zu haben - finde den Fehler - viel Spaß! ;) ). Zum anderen hat solch technischer Code nichts in einer Klasse zu suchen, die Geschäftslogik implementiert. Durch die statische Zugriffsmethode wird das Testen unheimlich erschwert. Die Klasse wird zu einer globalen Variable. Dependencykontrolle wird schwer usw.

Reicht das? ;)

Es spricht nichts dagegen, sicherstellen zu wollen, dass es von einer Klasse nur 1 Instanz gibt. Dies kontrolliert man dann aber besser mit einem Container (z.B. Spring).

* Dependencies selbst besorgen (lookups oder Erzeugung mit new)

Klassen die nicht nach dem Prinzip der DependencyInjection arbeiten instantiieren ihre Kollaborateure selbst oder machen einen Lookup (z.B. JNDI oder einfache FooBar.getInstance()). Dies sorgt dafür, dass versteckte Abhängigkeiten entstehen, die nicht an der Klassenschnittstelle sichtbar sind. Dies erhöht den Testaufwand ungemein. Ausserdem verletzt die Klasse Separation of Concerns, da sie (Geschäfts-)Logik implementiert und Logik, um ihre Umgebung aufzubauen.

Workaround / Lösung: DependencyInjection benutzen.

* instanceof (in 90% der Fälle)
Der gebrauch von instanceof ist meist an Anzeichen für ein falsches Design , welches besser mit Vererbung realisiert wird.

Java:
public void accelerate(Vehicle vehicle) {

  speed = vehicle.getSpeed();

  if (vehicle instanceof Car) {
    vehicle.setSpeed(speed +10);
  } else if (vehicle instanceof Bike) {
    vehicle.setSpeed(speed + 1);
  }
}
Hier sind Car und Bike Subklassen von Vehicle. Eine besseres Design wäre folgendes:

Java:
public abstract class Vehicle() {

  public abstract void accelerate();
}

public class Car extends Vehicle {

  public void accelerate() {
    this.speed += 10;
  }
}

public class Bike extends Vehicle {

  public void accelerate() {
    this.speed += 1;
  }
}

Gruß
Ollie

REINHAUN!
 
Hallo Oliver,
Mensch den Beitrag fand ich echt super. Hat mich veranlasst mal einige Schlagwörter weiter nachzuschlagen und mein Verständnis zu bereichern, Danke.

Der gebrauch von instanceof ist meist an Anzeichen für ein falsches Design , welches besser mit Vererbung realisiert wird.
Ich verwende so manches Mal instanceof allerdings weniger so wie in Deinem Beispiel, sondern häufiger, um die ein oder andere zusäzliche Funktion zu nutzen, die nicht alle Klassen selbst, wenn sie alle von einer abstammen, haben.
Ich weiß viele Fallunterscheidungen zu haben ist oftmals ein Indikator für unzureichendes OO-Design. Aber irgendwie will mir das vermeiden von instanceof nicht immer gelingen.
Wenn ich mal Dein Beispiel "entführen" darf...
Nehmen wir mal an wir wollten irgendwo z.B. eine Funktion wahrnehmen die car hat aber nicht bike und umgekeht (Scheibenwischer ein und ausschalten beim Auto)
dann könnte man zwar instanceof umgehen, indem man für Bike dieselbe Methode definiert, die bliebe dann aber vermutlich unimplementiert. Vermutlich würde man hier ein Interface basteln, welches "einschaltenScheibenwischer" in vehicle einschließen würde.
Aber wenn man nun eine andere Funktion für Bike noch hätte (mal weit hergeholt) "Speichenschloss abschließen", oder besser noch "Ständer ausklappen", dann würde man ebenso dies in vehilce packen müssen (angenommen es wäre ein interface oder eine Abstracte Klasse). Kann dies dann nicht auch zu einem Dilemma führen? Man hätte dann eine "allwissende" Elternklasse (oder Interface), welche man dann auch immer wieder bereichern müsste, sobald man es mit einem vehicle zu tun hat welches Sonderfunktionen aufweist. Wie kann man in solchen Fällen eine Fallunterscheidung mit instanceof abwenden?
 
Zuletzt bearbeitet:
Also, grundsätzlich gehören die Methoden in die Klasse, zu deren Abstraktion sie passen. Scheibenwischer ein/aus gehört also an Car, Speichenschloss abschließen zu Bike usw. Wenn man dann irgendwie in die Situation kommt, eine Instanz von Vehicle zu haben und nun spezielle Methoden rufen will / muss, kann es ganz gut sein, dass man in Vehicle eine Methode einführt, die für diesen Fall eine Methode auf der Superklasse einzuführen, die zu deren Abstraktion passt. Z.B. könnte es für die zwei besagten Fälle Sinn machen eine handleRain() oder handleWeather(Weather weather) einzuführen und dann die konkreten Klassen halt in der Implementierung startWiper() (für Car) rufen zu lassen. Das Abschließen des Fahrrads könnte man mit secure() auf Vehicle wrappen. Ein Fahrzeug sollte man nämlich grundsätzlich sichern, wenn man es verlässt ;). So kann eine Subklasse auch zum Ausdruck bringen, dass es nichts tun will in dem es die Implementierung einfach leer lässt.

Falls man nicht drum herum kommt, wirklich Methoden der konkreten Klassen zu rufen, dann ist ist ein Cast unumgänglich. Allerdings versucht man sowas halt soweit wie möglich zu vermeiden.

Gruß
Ollie
 
Der gebrauch von instanceof ist meist an Anzeichen für ein falsches Design , welches besser mit Vererbung realisiert wird.
Scott Meyers hat das in seinem Buch „Effective C++“ (für das ich ganz nebenbei zusammen mit „More Effective C++“ eine ausdrückliche Leseempfehlung aussprechen kann) wie ich finde recht schön formuliert:
Scott Meyers hat gesagt.:
Anytime you find yourself writing code of the form "if the object is of type T1, then do something, but if it's of type T2, then do something else," slap yourself.
;-)

Grüße,
Matthias
 
Naja ich habe nicht selten das Problem dass ich nicht ander als mit instanceof arbeiten muss, zumal dann wenn ich eine Klasse implementiere, die Vorgaben aus dem Java-Framework kommen. Typisches Beispiel wäre
Code:
actionPerformed(ActionEvent e)
Denn wenn ich da unter gewissen Umständen eigene ActionEvents kredenze, wie an die "neue" Methode drankommen? Natürlich ein Typecast OK! Aber was tun, wenn ich in einer Situation bin, dass ich unterschiedliche ActionEvents bekommen kann unteranderem die Ursprünglichen? Mal nur so als Szenario.

Soweit ich mal gehört habe, und was ich intuitiv bestetigen würde, sind viele Fallunterscheidungen zu haben unabhängig ob Typabfrage oder nicht kein gutes Zeichen.
Da habe ich Programme in Wartung (uiuiui :eek:)
 
Zuletzt bearbeitet:
Hallo,

instanceof überhaupt nicht zu verwenden halte ich für unpraktisch.
Wenn in Java Code das instanceof Schlüsselwort verwendet wird ist das
in der Regel ein Zeichen dafür das an einigen Stellen zu statisch gegen bestimmte
Implementierungen Programmiert wurde, was man statt dessen besser
dynamisch per Polymorphismus realisiert worden wäre. Wie meine Vorredner schon sagten.
Wenn man Einfluss auf das Design der entsprechenden Klassen hat kann man das auch
wunderbar so machen, jedoch sieht das in der Praxis ganz anders aus.
Aufgrund des Designs bestimmter Klassen der verwendeten (third-party) Bilbiotheken bzw. der Java Laufzeitbibliothek selbst kommt man IMHO bei generischem / reflektivem
Code nicht um Laufzeittypprüfungen herum. Wenn man hier nun anstatt x instanceof IFoo ein
IFoo.class.isInstance(x) ist das IMHO eher umständlicher.

Gruß Tom
 
Zurück