Korrekte Vererbungshierarchie

Was ist richtig?

  • Rechteck extends Quadrat

    Stimmen: 0 0,0%
  • Beides...

    Stimmen: 0 0,0%
  • Nichts von alledem...

    Stimmen: 0 0,0%

  • Anzahl der Umfrageteilnehmer
    155
Status
Nicht offen für weitere Antworten.
B

Beni

Gast
Man liest immerwieder dieses tolle Beispiel "Quadrat extends Rechteck". Aber ist das richtig? Ich meine, ein Quadrat besitzt weniger Funktionalität als ein Rechteck (nur eine statt zwei Seitenlängen).

Ich denke "Nichts von alledem..." wäre die korrekte Antwort, was denkt ihr? ???:L
 
M

maki

Gast
Man liest immerwieder dieses tolle Beispiel "Quadrat extends Rechteck". Aber ist das richtig? Ich meine, ein Quadrat besitzt weniger Funktionalität als ein Rechteck (nur eine statt zwei Seitenlängen).

Ich denke "Nichts von alledem..." wäre die korrekte Antwort, was denkt ihr? icon_scratch.gif
Ein Quadrat ist eine Spezialisierung von einem Rechteck, demnach wäre eine Möglichkeit zu sagen, dass Quadrat eine Unterklasse von Rechteck ist.

Auf der anderen Seite würde eine Methode (isSquare) in der Rechteck Klasse auch reichen, je nachdem wie man es braucht.
 

tfa

Top Contributor
Vom OO-Standpunkt aus betrachtet ist "Nichts von alledem" die korrekte Antwort. Geometrisch ist ein Quadrat selbstverständlich schon ein Rechteck.
 

Marco13

Top Contributor
:lol: Das hat mich eben auch mal dazu veranlasst, das große goOrakel zu fragen :D

"Square extends Rectangle": ca. 1000 Ergebnissse
"Rectangle extends Square": ca. 100 Ergebnisse

Wenn man nach beidem sucht, findet man auch diese PDF-Datei
http://www.it.iitb.ac.in/~it611/Resources/Session3-AnalysisDesign.pdf
in der auf die verschiedenen Möglichkeiten etwas genauer eingegangen wird.

Meine Antwort ist: Beides. (Kommt darauf an, was man abbilden will)
 

tfa

Top Contributor
Marco13 hat gesagt.:
:lol: Das hat mich eben auch mal dazu veranlasst, das große goOrakel zu fragen :D

"Square extends Rectangle": ca. 1000 Ergebnissse
"Rectangle extends Square": ca. 100 Ergebnisse
Such in dem Zusammenhang mal nach "Liskov Substitution Principle", bzw. Brechung desselben.
Dieses Beispiel wird in der Lehre gerne verwendet, um zu zeigen, dass eine "is-A"-Beziehung in der
Realität nicht unbedingt ein "is-A" in der Objektorientierten Welt ist.

Wenn man nach beidem sucht, findet man auch diese PDF-Datei
http://www.it.iitb.ac.in/~it611/Resources/Session3-AnalysisDesign.pdf
in der auf die verschiedenen Möglichkeiten etwas genauer eingegangen wird.

Meine Antwort ist: Beides. (Kommt darauf an, was man abbilden will)

Die übliche Lehrmeinung ist wie gesagt: keins von beiden.
Der zitierte Link macht mich allerdings skeptisch, was die "Einfuhr" von Computer-Indern angeht... :lol:
 

Marco13

Top Contributor
Nun, was kümmert einen die "Lehrmeinung", wenn man ein konkretes Problem hat, das entweder durch die eine oder durch die andere Variante gelöst werden kann? Und genau die, die das Problem löst, ist im jeweiligen Fall die richtige - dass es dann irgendeinen (anderen) Zusammenhang und irgendeine Betrachtungsweise gibt, in der die gewählte Hierarchie "unpassend" ist, spielt nicht unbedingt eine Rolle - (auch wenn man die Möglichkeit dafür im Hinterkopf behalten sollte). Die Objektorientierte Welt ist ein eingeschränktes ( :meld: :wink: ) Modell der realen Welt, und wenn bei dem, was man modellieren will, gilt
ein Rechteck ist ein Quadrat (mit einer zusätzlichen Seitenlänge) oder
ein Quadrat ist ein Rechtek (mit immer gleichen Seitenlängen)
dann modelliert man das eben so....
 

tfa

Top Contributor
Marco13 hat gesagt.:
Nun, was kümmert einen die "Lehrmeinung", wenn man ein konkretes Problem hat, das entweder durch die eine oder durch die andere Variante gelöst werden kann? ...

Klar kann man ein "konkretes" Problem vermeindlich lösen und dann später feststellen, dass noch viel konkretere Probleme durch seine Lösung entstehen. Und diese Square-Rectangle-Geschichte ist eben das Schulbeispiel dazu.

Wie würdest Du beispielsweise hiervon eine Klasse Square ableiten?

Code:
public class Rectangle {
   private int width;
   private int height;

   public int getHeight() { return height; }
   public int getWidth() { return width; }

   public void setHeight(int p) { height=p; } 
   public void setWidth(int p) { width=p; }

}
 
M

maki

Gast
Hmmm... ein altes Problem, das Beispiel das mir einfällt wären die Tierarten, Vögel können fliegen, legen Eier etc. Säugetiere gebären lebend und säugen...

Irgendwann steht man dann vor dem Problem, das man ein Platypus (Schnabeltier) abbilden muss. Ein Platypus legt Eier, hat Schwimmhäute, einen Schnabel, ein Fell und viele andere Dinge die eigentlich über mehrere Tierarten verteilt sind (gilt offiziell aber als Säugetier).

Die Lösung?
Eine Möglichkeit: Weg von der Implementierungsvererbung (extends) und hin zur Schnittstellenvererbung(implements), damit sind die Implementierungen immer spezifisch und die Schnittstellen allgemein.
 

Niki

Top Contributor
Code:
public class Square extends Rectangle{

   public void setHeight(int p) { super.setHeight(p); super.setWidth(p);}
   public void setWidth(int p) { this.setHeight(p); }

}
 

tfa

Top Contributor
Niki hat gesagt.:
Code:
public class Square extends Rectangle{

   public void setHeight(int p) { super.setHeight(p); super.setWidth(p);}
   public void setWidth(int p) { this.setHeight(p); }

}

Ok. Jetzt stell Dir folgende Methode vor:

Code:
public class Tools {
  /** 
   * Verzerrt ein beliebiges Rechteck zu einem flächengleichen Einheitsrechteck mit der Breite 1.
   * VORBEDINGUNG: rec ist ein Rechteck, width und height sind größer als 0.
   * NACHBEDINGUNG: rec hat width=1 und eine unveränderte Gesamtfläche.
   */ 
  public static void einheitsRechteck(Rectangle rec) {
      int flaeche = rec.getWidth()*rec.getHeight();
      rec.setWidth(1);
      rec.setHeight(flaeche);
  }
}

Was passiert, wenn Du dieser Methode ein Objekt Deiner Square-Klasse übergibst? Funktioniert sie dann noch?
 

Niki

Top Contributor
Nettes Beispiel. Ich würd halt einfach ein neues Rectangle erzeugen, anstatt das selbe zu verändern:
Code:
  public static Rectangle einheitsRechteck(Rectangle rec) {
      int flaeche = rec.getWidth()*rec.getHeight();
      rec = new Rectangle();
      rec.setWidth(1);
      rec.setHeight(flaeche);
      return rec;
  }
 

lhein

Top Contributor
In der Schule war die Aussage immer: "Das Quadrat ist eine Sonderform des Rechtecks."

Somit ergibt sich logischerweise für die meisten, daß das Quadrat seine Grundeigenschaften von Rechteck erbt. Die einzige Besonderheit ist doch, daß alle vier Seiten den selben Wert haben.

In der Objektorientierung macht diese Vererbungshierarchie aber nicht unbedingt Sinn. Da würde man sicherlich beide Objekte von etwas Allgemeinerem wie Viereck erben lassen.

lr
 

tfa

Top Contributor
Niki hat gesagt.:
Ich würd halt einfach ein neues Rectangle erzeugen, anstatt das selbe zu verändern:
Das wäre nur ein Workaround. Es ist wie gesagt nur ein einfaches Beispiel. In anderen Fällen ist es vielleicht nicht möglich, sich so leicht zu helfen. Deswegen sollte man sich immer an das LSP halten: Ein Subtyp muss unter allen Umständen an Stelle des Obertyps verwendet werden können.
 

Marco13

Top Contributor
Ich bin jetzt mal so frei, ganz unüberlegt zu behaupten, dass diese Bedingung nicht erfüllt werden kann. Schreibe ein beliebiges Testprogramm, wo Vererbung scheinbar LSP-konform eingesetzt wird, und ich zeige dir, wo es das Beispiel raushaut. (Es wird u.U. sehr konstruiert wirken, aber das LSP ist ein theoretisches Konstrukt, und auch wenn Theorie und Praxis in wenigen Bereichen so eng verbunden sind, die in der Informatik, so sind sie selbst dort nicht dasselbe)
 

ms

Top Contributor
Meiner Ansicht nach ist es "nichts von alledem".
Die Frage, die sich mir gestellt hat, war: Warum sollte sich in diesem Fall ein Typ durch die Werte einer Eigenschaft definieren und nicht wie bisher angenommen und angewendet über eine besondere Eigenschaft selbst (also nicht deren Wert)?
Nur weil Länge und Breite gleich sind ist es gleich ein eigener Typ! Da muss das Ding schon mehr können. :)
Daher existieren für mich in Funktionalität und Eigenschaft keine Unterschiede zwischen Quadrat und Rechteck.
Sicherlich, die Besonderheit der gleich langen Seiten existiert, aber rechtfertigt für mich keinen eigenen Typ.

ms
 

tfa

Top Contributor
Marco13 hat gesagt.:
Ich bin jetzt mal so frei, ganz unüberlegt zu behaupten, dass diese Bedingung nicht erfüllt werden kann. Schreibe ein beliebiges Testprogramm, wo Vererbung scheinbar LSP-konform eingesetzt wird, und ich zeige dir, wo es das Beispiel raushaut. (Es wird u.U. sehr konstruiert wirken, aber das LSP ist ein theoretisches Konstrukt, und auch wenn Theorie und Praxis in wenigen Bereichen so eng verbunden sind, die in der Informatik, so sind sie selbst dort nicht dasselbe)

Es steht ja nicht unter Strafe, das LSP zu verletzen. In der Java-API gibt es selbst Beispiele hierfür (z.B. Frame.add(Component) vs. JFrame.getContentPane().add(Component)).
Ich behaupte nicht, dass Software, die das LSP verletzt, zwangläufig schlecht ist oder nicht funktioniert.
Aber wenn man schon weiß, dass ein LSP gibt und wie es funktioniert (es ist wirklich nicht nur ein theoretisches Konstrukt), dann sollte man sich bemühen, es einzuhalten.


Eine saubere Rectangle-Square-Variante wäre folgende (wahrscheinlich zu trivial, um da was "rauszuhauen"):

Code:
public abstract class Shape {
    public int getArea();
}

public class Rectangle extends Shape { 
    private int width; 
    private int height; 

    public Rectangle(int width, int height) { this.width=width; this.height=height; }
    
    public int getHeight() { return height; } 
    public int getWidth() { return width; } 

    public void setHeight(int p) { height=p; } 
    public void setWidth(int p) { width=p; } 

    public int getArea() { return height*width; }
}

public class Square extends Shape { 
    private int size; 
    
    public Square(int size) { this.size = size; }
    
    public int getSize() { return size; } 
    public void setSize(int p) { size=p; }     

    public int getArea() { return size*size; }
}
 
M

maki

Gast
Damit schließt sich Vererbung schon aus, oder?
Ja, aber wie sieht es mit der Fortpflanzung aus?

"gebäreLebend" gibt's ja nicht für dieses Säugetier, sondern ein "legeEier".
Wenn man jetzt eine Vererbungshierarchie hat, in der die Methode "gebäreLebend" schon in der Superklasse (zB Säugetier) festgeschrieben ist, steht man vor einem Problem, schliesslich würde man eigentlich die Methode "legeEier" der Superklasse Vogel benutzen, aber die ist ja leider nicht mit Sägetier verwandt.

Mit Interfaces wäre das schon einfacher.
 

byte

Top Contributor
Das Beispiel zeigt auch sehr gut, warum Komposition häufig sinnvoller ist als Vererbung.
Ich möchte tfas Code mal etwas anpassen:

Code:
public abstract class Shape {
    public int getArea();
}

public class Rectangle extends Shape { 
    private int width; 
    private int height; 

    public Rectangle(int width, int height) { this.width=width; this.height=height; }
    
    public int getHeight() { return height; } 
    public int getWidth() { return width; } 

    public void setHeight(int p) { height=p; } 
    public void setWidth(int p) { width=p; } 

    public int getArea() { return height*width; }
}

public class Square extends Shape {
    private Rectangle rectangle;  
    
    public Square(int size) { rectangle = new Rectangle(size, size); }
    
    public int getSize() { return rectangle.getWidth(); } 
    public void setSize(int p) { rectangle.setHeight(p); rectangle.setWidth(p); }     

    public int getArea() { return rectangle.getArea(); }
}
 

ms

Top Contributor
byto hat gesagt.:
Das Beispiel zeigt auch sehr gut, warum Komposition häufig sinnvoller ist als Vererbung.
Ich möchte tfas Code mal etwas anpassen:

Code:
public abstract class Shape {
    public int getArea();
}

public class Rectangle extends Shape { 
    private int width; 
    private int height; 

    public Rectangle(int width, int height) { this.width=width; this.height=height; }
    
    public int getHeight() { return height; } 
    public int getWidth() { return width; } 

    public void setHeight(int p) { height=p; } 
    public void setWidth(int p) { width=p; } 

    public int getArea() { return height*width; }
}

public class Square extends Shape {
    private Rectangle rectangle;  
    
    public Square(int size) { rectangle = new Rectangle(size, size); }
    
    public int getSize() { return rectangle.getWidth(); } 
    public void setSize(int p) { rectangle.setHeight(p); rectangle.setWidth(p); }     

    public int getArea() { return rectangle.getArea(); }
}
Dann stimmt aber nicht mehr die Aussage dass ein Quadrat auch ein Rechteck ist.

ms
 

Marco13

Top Contributor
tfa hat gesagt.:
Eine saubere Rectangle-Square-Variante wäre folgende (wahrscheinlich zu trivial, um da was "rauszuhauen"):
Zu trivial, da das zwei vollkommen getrennte Klassen sind, die nichts miteinander zu tun haben, weil man das getArea auch weglassen könnte, und die beiden dann (Juchhu...) ja immernoch von Object erben. Solange die Objekte (aus Sicht der abstrakten Oberklasse!) "immutable" sind, ist das "raushauen" schwierig.

In Java ist aber selbst das nicht unmöglich. Wenn ich jetzt was mit "getClass().getName().equals(...)" schreiben würde, wäre das genau das "konstruierte", was ich beim Schreiben des letzten Beitrages im Hinterkopf hatte, aber ... es wäre ein gültiges Beispiel, wo man sieht, dass die Anforderung in der Theorie theoretisch IMMER, aber in der Praxis theoretisch NIE erfüllbar ist :cool: :meld: :autsch:
 

ms

Top Contributor
tfa hat gesagt.:
ms hat gesagt.:
Dann stimmt aber nicht mehr die Aussage dass ein Quadrat auch ein Rechteck ist.

Richtig! :toll: :toll:
Ein Quadrat ist aber ein Rechteck!?!

Ich verstehe noch immer nicht, warum man überhaupt ein Quadrat als eigenen Typ definiert.
Bei einer Klasse Mensch, die als Eigenschaft einen Geldbetrag hat würde man ja auch nicht ab einer gewissen Summe einen neuen Typ ReicherMensch definieren.

edit:
In der Klasse Rechteck würde doch lediglich eine Methode
Code:
boolean isSquare() {}
genügen.

ms
 

tfa

Top Contributor
ms hat gesagt.:
Ein Quadrat ist aber ein Rechteck!?!
Nein, ist es nicht (siehe oben).

ms hat gesagt.:
Ich verstehe noch immer nicht, warum man überhaupt ein Quadrat als eigenen Typ definiert.
Bei einer Klasse Mensch, die als Eigenschaft einen Geldbetrag hat würde man ja auch nicht ab einer gewissen Summe einen neuen Typ ReicherMensch definieren.

Natürlich würde man das nicht. Wie gesagt, nur ein Beispiel. Ich würde überhaupt nur eine Klasse Rechteck definieren und dann für Quadrat eine Factory-Methode und eine Prädikats-Methode hinzufügen:

Code:
public class Rectangle {
   ...
   public static Rectangle createSquare(int) {...}
   public boolean isSquare() {...}
}

Die Delegations-Lösung von byto ist aber auch eine Überlegung wert.
 

byte

Top Contributor
ms hat gesagt.:
Ich verstehe noch immer nicht, warum man überhaupt ein Quadrat als eigenen Typ definiert.
Um an irgendeiner Stelle damit zu arbeiten? Klar, wenn Du in Deinem Kontext nie Quadrate von Rechtecken unterscheiden musst, dann brauchst Du auch kein Quadrat zu definieren. Aber vielleicht brauchst Du ja in einem Kontext nur Quadrate, in einem anderen nur Rechtecke und in noch einem anderen beides.
 

tfa

Top Contributor
ms hat gesagt.:
tfa hat gesagt.:
ms hat gesagt.:
Ein Quadrat ist aber ein Rechteck!?!
Nein, ist es nicht (siehe oben).[/code]
Öhm.. ich glaub ich steh auf der Leitung.
Wie definierst du denn ein Rechteck bzw. Quadrat?

tfa hat gesagt.:
Vom OO-Standpunkt aus betrachtet ist "Nichts von alledem" die korrekte Antwort. Geometrisch ist ein Quadrat selbstverständlich schon ein Rechteck.
 

ms

Top Contributor
byto hat gesagt.:
Um an irgendeiner Stelle damit zu arbeiten? Klar, wenn Du in Deinem Kontext nie Quadrate von Rechtecken unterscheiden musst, dann brauchst Du auch kein Quadrat zu definieren. Aber vielleicht brauchst Du ja in einem Kontext nur Quadrate, in einem anderen nur Rechtecke und in noch einem anderen beides.
Das ist schon richtig, aber rechtfertigt dass einen eigenen Typ?
Welchen Mehrwert hast du von einer Klasse Quadrat im Vergleich zu einem Rechteck?

ms
 

byte

Top Contributor
Dieses Beispiel ist natürlich recht trivial. Aber wenn ich im Code diverse Stellen habe, wo ich definitiv nur mit Quadraten arbeiten will, dann ist es schon sinnvoll einen Typ Quadrat zu haben. Du musst dann nicht jedes mal mit isSquare() die Eigenschaft überprüfen. Es resultieren potentiell weniger Laufzeitfehler bzw. ein vereinfachtes Exception Handling. Denn Du musst Dir nicht ständig überlegen, was im Fehlerfall passiert (also kein Quadrat reinkommt), dafür sorgt ja der Compiler.
Kurz gesagt: Der Mehrwert kommt eben daher, dass Du objektorientiert bist. ;)
 

ms

Top Contributor
Du hast natürlich recht, wenn du sagst, dass du nur mit Quadraten arbeiten willst.
Aber ich behaupte einfach mal ganz frech, es macht keinen Unterschied ob du mit Quadraten oder Rechtecken arbeitest.
Zumindest will mir einfach kein Beispiel dafür einfallen, weil meiner Ansicht nach nicht der Wert einer Eigenschaft Typ-bestimmend ist sondern eine Eigenschaft selbst. Rechteck und Quadrat haben beide dieselben Eigenschaften und Methoden. Man würde mit beiden Typen immer zum selben Ergebnis kommen. Daher fällt für mich das Quadrat als Typ weg.

Aber vielleicht bin ich da etwas zu kurzsichtig und es gibt ein Beispiel wo es Sinn macht Rechteck und Quadrat als unterschiedliche Typen zu haben.

ms
 

SnooP

Top Contributor
Manchmal willst du halt die Unterscheidung haben... stell dir ein Malprogramm vor, welches die Icons Rechteck und Quadrat hat. Wenn du ein Rechteck malen willst, kannst du das beliebig skalieren - beim Quadrat soll eine Veränderung in x-Richtung sich genauso auf die y-Richtung auswirken... schwupp hast du da die Unterscheidung... und dann musst du dir halt überlegen, wie du's machen willst ;)

und genau da wäre es halt falsch eine Methode des Obertyps entgegen der zugesicherten Eigenschaft zu überschreiben.
 

happy_robot

Bekanntes Mitglied
tfa hat gesagt.:
Vom OO-Standpunkt aus betrachtet ist "Nichts von alledem" die korrekte Antwort. Geometrisch ist ein Quadrat selbstverständlich schon ein Rechteck.
dem würde ich so nicht ohne erläuterung folgen wollen.

grundsätzlich ist ein quadrat durchaus ein spezialfall eines rechtecks und somit wohl eine überlegung wert.

viel wichtiger ist die frage ob gewisse attribut-werte einer klasse, was hier der fall ist, eine spezialisierung rechtfertigen.
das ist sicherlich nicht so, denn das würde heissen daß der klassentyp einer objekt-instanz zur laufzeit abhängig von seinen attributwerten sein kann.

erst eine quadrat-spezifische notwendige implementierung würde eine eigene klasse rechtfertigen.
 

happy_robot

Bekanntes Mitglied
jepp...habe da aufgehört zu lesen wo es zu konkret um irgendwelche implementierungen oder die unterschiede eines quadrat und eines rechteck ging.
auch beim nochmaligen "richtigen" durchlesen des ganzen threads erschliesst sich mir nicht wie dies das eigentliche problem transparenter machen soll. daher glaube ich nicht das diese art der betrachtung hilfreich für die generelle entscheidung der notwendigkeit einer spezialisierung ist.

und noch mal: wenn bestimmte attributzustände eine eigene klasse rechtfertigen hätte dies zur folge daß ein objekt die klasse zur laufzeit ändern können sollte.

oder mal als frage formuliert: was ist wenn eine instanz der klasse Rechteck zur laufzeit gleiche seitenlängen zugewiesen bekommt? ???:L

was kommt denn als nächstes? eine abstrakte Ampel-Basisklasse mit drei Spezialisierungen "AmpelRot", "AmpelGelb" und "AmpelGruen" ? :roll:
 

tfa

Top Contributor
Darum ging es ja auch überhaupt nicht. Das ursprüngliche Problem war, ob man Rechteck von Quadrat ableiten sollte oder Quadrat von Rechteck oder ob man nichts von dem machen sollte. Die Frage, ob eine spezialisierte Quadrat-Klasse gerechtfertigt ist, ist davon völlig unabhängig. Das lenkt nur von der eigentlichen Fragestellung ab. Stell Dir einfach vor, Du brauchst eine Quadrat-Klasse und eine Rechteck-Klasse (der Kunde, der Boss, der Professor während der Software-Engineering-Prüfung wollen es so). Wie würdest Du die modellieren? Es ist eben nur ein einfaches Beispiel zur Erklärung grundlegender Prinzipien des Objektorientierten Entwurfs. Ich find's immer wieder erstaunlich, dass das zu so großen Kontroversen führt...
 

HLX

Top Contributor
Das liegt ganz einfach daran, dass es für solche Probleme eigentlich keine Musterlösung gibt. Eine Zusatzbedingung in der Aufgabe reicht schon aus um das Modell wieder völlig ander aussehen zu lassen.

Ohne Nebenbedingungen würde ich sagen Quadrat extends Rechteck, weil Spezialisierung. Das kann man auch gut im Code nachvollziehen:
Code:
public class Quadrat extends Rechteck {

    public Quadrat(double kantenlaenge) {
        super(x,x);
    }
}
Wie sähe das wohl andersrum aus. :wink:

Prinzipiell würde ich allerdings beide von Shape ableiten, weil es in der Praxis immer noch weitere Anforderungen gibt, die man auf dem obigen Wege später schlecht erfüllen kann.
 

byte

Top Contributor
happy_robot hat gesagt.:
oder mal als frage formuliert: was ist wenn eine instanz der klasse Rechteck zur laufzeit gleiche seitenlängen zugewiesen bekommt? ???:L
Dann wirft man eine ARectangleIsNotASquareException. :bae:
 

happy_robot

Bekanntes Mitglied
tfa hat gesagt.:
Darum ging es ja auch überhaupt nicht. Das ursprüngliche Problem war, ob man Rechteck von Quadrat ableiten sollte oder Quadrat von Rechteck oder ob man nichts von dem machen sollte. Die Frage, ob eine spezialisierte Quadrat-Klasse gerechtfertigt ist, ist davon völlig unabhängig. Das lenkt nur von der eigentlichen Fragestellung ab. Stell Dir einfach vor, Du brauchst eine Quadrat-Klasse und eine Rechteck-Klasse (der Kunde, der Boss, der Professor während der Software-Engineering-Prüfung wollen es so). Wie würdest Du die modellieren? Es ist eben nur ein einfaches Beispiel zur Erklärung grundlegender Prinzipien des Objektorientierten Entwurfs. Ich find's immer wieder erstaunlich, dass das zu so großen Kontroversen führt...
ähhhh...klar geht es darum.
wenn es darum geht zu klären ob man was von was ableiten sollte dann ist die überlegung ob eine ableitung generell sinn macht durchaus elementar.
und wenn du es trotzdem irgendwie festlegen willst ist's doch auch klar. das quadrat ist eine SPEZIELLE form des rechtecks. also ist die richtung doch klar und wenn ich eine quadrat und rechteck-klasse brauche baue ich eine deutlich generelle klasse (z.b. Shape) die nichts von dimensionen und formen weiß.

also was soll die diskussion??
 

ms

Top Contributor
byto hat gesagt.:
happy_robot hat gesagt.:
oder mal als frage formuliert: was ist wenn eine instanz der klasse Rechteck zur laufzeit gleiche seitenlängen zugewiesen bekommt? ???:L
Dann wirft man eine ARectangleIsNotASquareException. :bae:
Naja, keine gute Idee.
Dann hätte man bei Snoop's Beispiel wo skaliert wird ein Problem, wenn Seite A zuvor größer als Seite B war und danach B größer als A werden soll.

Snoop's Beispiel mit dem Skalieren ist ein gutes Argument für einen eigenen Typ Quadrat.
Allerdings steht das von happy_robot mit Berechtigung dagegen, was auch meine Ansicht ist.
Das Problem ist, dass wir es beim Skalieren hier mit Typen zu tun haben, die sich zur Laufzeit gänzlich ändern können.
Quadrat => Rechteck
Kreis => Ellipse
Dreieck => Trapez (Länge der Oberseite wird 0)

bzw. kann man das generell ausgehend von einem Polygon durchspielen.

ms
 
S

SlaterB

Gast
tfa hat gesagt.:
Ok. Jetzt stell Dir folgende Methode vor:

Code:
public class Tools {
  /** 
   * Verzerrt ein beliebiges Rechteck zu einem flächengleichen Einheitsrechteck mit der Breite 1.
   * VORBEDINGUNG: rec ist ein Rechteck, width und height sind größer als 0.
   * NACHBEDINGUNG: rec hat width=1 und eine unveränderte Gesamtfläche.
   */ 
  public static void einheitsRechteck(Rectangle rec) {
      int flaeche = rec.getWidth()*rec.getHeight();
      rec.setWidth(1);
      rec.setHeight(flaeche);
  }
}

Was passiert, wenn Du dieser Methode ein Objekt Deiner Square-Klasse übergibst? Funktioniert sie dann noch?

warum so kompliziert?

Code:
public class Tools {

  public static void checkRectangle(Rectangle rec) {
      rec.setWidth(3);
      rec.setHeight(4);
      if (rec.getArea() != 12) {
           // Boom
      }
  }
}
;)
 

tfa

Top Contributor
SlaterB hat gesagt.:
warum so kompliziert?

Code:
public class Tools {

  public static void checkRectangle(Rectangle rec) {
      rec.setWidth(3);
      rec.setHeight(4);
      if (rec.getArea() != 12) {
           // Boom
      }
  }
}
;)

Gute Idee. Vielleicht wird's als Unit-Test noch deutlicher:
Code:
@Test
public void test1() {
    Rectangle rec = new Rectangle(1,2);
    rec.setWidth(3);
    rec.setHeight(4);
    assertEquals( rec.getArea(), 12);
}

@Test
public void test2() {
    Rectangle rec = new Square(1);
    rec.setWidth(3);
    rec.setHeight(4);
    assertEquals( rec.getArea(), 12);
}
 

Marco13

Top Contributor
Und wo steht überhaupt eine "Aufgabe" ???:L :autsch:

Um das nochmal zu bekräftigen: Ich denke, die Wahl der Vererbungshierarchie hängt davon ab, was man modellieren will. Für drei der genannten Alternativen kann man sich Szenarien ausdenken, weswegen man (IMHO(!)) zwei der Antwortmöglichkeiten ankreuzen kann, nämlich entweder "Keins von beidem" oder "Beides". (Keins von beidem kann richtig sein, oder beides kann richtig sein - wenn auch nicht gleichzeitig) Und ich (als geborener Optimist :roll: ) habe natürlich "Beides" gewählt ....
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Wie tief darf eine Vererbungshierarchie sein? Softwareentwicklung 10

Ähnliche Java Themen

Neue Themen


Oben