# Korrekte Vererbungshierarchie



## Beni (12. Dez 2007)

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


----------



## maki (12. Dez 2007)

> 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 (12. Dez 2007)

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


----------



## Marco13 (12. Dez 2007)

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

"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 (12. Dez 2007)

Marco13 hat gesagt.:
			
		

> :lol: Das hat mich eben auch mal dazu veranlasst, das große goOrakel zu fragen
> 
> "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 (12. Dez 2007)

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....


----------



## SnooP (12. Dez 2007)

http://de.wikipedia.org/wiki/Liskovsches_Substitutionsprinzip


----------



## tfa (12. Dez 2007)

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?


```
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; }

}
```


----------



## maki (12. Dez 2007)

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 (12. Dez 2007)

```
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 (12. Dez 2007)

Niki hat gesagt.:
			
		

> ```
> public class Square extends Rectangle{
> 
> public void setHeight(int p) { super.setHeight(p); super.setWidth(p);}
> ...



Ok. Jetzt stell Dir folgende Methode vor:


```
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 (12. Dez 2007)

Nettes Beispiel. Ich würd halt einfach ein neues Rectangle erzeugen, anstatt das selbe zu verändern:

```
public static Rectangle einheitsRechteck(Rectangle rec) {
      int flaeche = rec.getWidth()*rec.getHeight();
      rec = new Rectangle();
      rec.setWidth(1);
      rec.setHeight(flaeche);
      return rec;
  }
```


----------



## lhein (12. Dez 2007)

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 (12. Dez 2007)

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 (12. Dez 2007)

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 (12. Dez 2007)

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


----------



## ms (12. Dez 2007)

maki hat gesagt.:
			
		

> Ein Platypus legt Eier, *hat* Schwimmhäute, einen Schnabel,...


Damit schließt sich Vererbung schon aus, oder?

ms


----------



## tfa (12. Dez 2007)

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"):


```
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; }
}
```


----------



## maki (12. Dez 2007)

> 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.


----------



## ARadauer (12. Dez 2007)

kommt immer drauf an, was man schlussendlich damit machen möchte.


----------



## tfa (12. Dez 2007)

maki hat gesagt.:
			
		

> Mit Interfaces wäre das schon einfacher.



Richtig. Oder mit so tollen Sachen wie Mix-Ins.


----------



## byte (12. Dez 2007)

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


```
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 (12. Dez 2007)

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:
> 
> 
> ...


Dann stimmt aber nicht mehr die Aussage dass ein Quadrat auch ein Rechteck ist.

ms


----------



## tfa (12. Dez 2007)

ms hat gesagt.:
			
		

> Dann stimmt aber nicht mehr die Aussage dass ein Quadrat auch ein Rechteck ist.



Richtig!  :toll:  :toll:


----------



## Marco13 (12. Dez 2007)

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    :meld:  :autsch:


----------



## ms (12. Dez 2007)

tfa hat gesagt.:
			
		

> ms hat gesagt.:
> 
> 
> 
> ...


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 
	
	
	
	





```
boolean isSquare() {}
```
 genügen.

ms


----------



## tfa (12. Dez 2007)

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:


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

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


----------



## byte (12. Dez 2007)

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.


----------



## ms (12. Dez 2007)

tfa hat gesagt.:
			
		

> ms hat gesagt.:
> 
> 
> 
> ...


Öhm.. ich glaub ich steh auf der Leitung.
Wie definierst du denn ein Rechteck bzw. Quadrat?

ms


----------



## tfa (12. Dez 2007)

ms hat gesagt.:
			
		

> tfa hat gesagt.:
> 
> 
> 
> ...





			
				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 (12. Dez 2007)

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 (13. Dez 2007)

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 (13. Dez 2007)

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 (13. Dez 2007)

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 (13. Dez 2007)

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.


----------



## byte (13. Dez 2007)

happy_robot hat gesagt.:
			
		

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


Offenbar hast Du den Thread nicht zu Ende gelesen. :roll:


----------



## tfa (13. Dez 2007)

happy_robot hat gesagt.:
			
		

> tfa hat gesagt.:
> 
> 
> 
> ...



Die Erläuterung hierzu findest Du in diesem Thread.


----------



## happy_robot (14. Dez 2007)

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 (14. Dez 2007)

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 (14. Dez 2007)

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:

```
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 (14. Dez 2007)

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 (14. Dez 2007)

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??


----------



## tfa (14. Dez 2007)

happy_robot hat gesagt.:
			
		

> also was soll die diskussion??



*seufz*


----------



## ms (14. Dez 2007)

byto hat gesagt.:
			
		

> happy_robot hat gesagt.:
> 
> 
> 
> ...


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


----------



## SlaterB (14. Dez 2007)

tfa hat gesagt.:
			
		

> Ok. Jetzt stell Dir folgende Methode vor:
> 
> 
> ```
> ...



warum so kompliziert?


```
public class Tools {

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


----------



## happy_robot (14. Dez 2007)

tfa hat gesagt.:
			
		

> *seufz*


spezialisierungen auf attributebene zu begründen widerspricht jeglicher OOP! 
das wird auch mit rumseufzen leider nich' besser (auch mittel- und langfristig nicht  :roll: ). 
nun denn.......


----------



## tfa (14. Dez 2007)

SlaterB hat gesagt.:
			
		

> warum so kompliziert?
> 
> 
> ```
> ...



Gute Idee. Vielleicht wird's als Unit-Test noch deutlicher:

```
@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);
}
```


----------



## HLX (14. Dez 2007)

Wo steht in der Ursprungsaufgabe etwas von protected/public getter und setter?


----------



## tfa (14. Dez 2007)

Wo steht, dass es keine geben darf?


----------



## Marco13 (14. Dez 2007)

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 ....


----------



## HLX (14. Dez 2007)

Ich sehe das vorhandensein solcher Methoden als Zusatzbedingung. Sie macht eine gegenseitige Ableitung unsinnig. Hätte ich im Gegensatz dazu nur Getter, weil das Objekt z.B. von außen unveränderlich sein soll, sieht die Sache u.U. schon wieder anders aus.

@Marco13: nenn es von mir aus auch Beispiel  :wink:


----------



## tfa (14. Dez 2007)

HLX hat gesagt.:
			
		

> Ich sehe das vorhandensein solcher Methoden als Zusatzbedingung. Sie macht eine gegenseitige Ableitung unsinnig. Hätte ich im Gegensatz dazu nur Getter, weil das Objekt z.B. von außen unveränderlich sein soll, sieht die Sache u.U. schon wieder anders aus.



Korrekt!  :toll:  :toll:


----------

