Geometry Objektorientierung

hi,
ich habe folgende Aufgabe:

In dieser Aufgabe sollen Sie eine kleine Geometrie-Bibliothek implementieren. Betrachten Sie dazu die abstrakte Klasse geometry.Geometry in der Bibliothek geometrylib.jar Diese besitzt folgende Methoden:
• dimensions() - Gibt die Anzahl der Dimensionen dieser Geometry zurück. Eine Geometry hat mindestens 2 Dimensionen.
• encapsulate(Geometry other) - Umgibt diese und die übergebene Geometry mit der gleichen Anzahl an Dimensionen mit einer neuen Geometry und gibt diese zurück. Die neue Geometry muss einerseits eine minimale Ausdehnung haben und andererseits diese und die übergebene Geometry vollständig enthalten. Wenn zwei Geometry - Instanzen eine un- terschiedliche Anzahl an Dimensionen haben, wird null zurückgeliefert.
• volume() - Gibt das Volumen einer Geometry als double zurück. Im zweidimensionalen Fall ist dies die Fläche einer Geometry.
Erweitern Sie die Klasse Geometry nun um die folgenden Klassen.
• Point2D-EinzweidimensionalerPunktdermitzweidouble-Wertenerzeugtwerdenkann.
• Point - Repräsentiert einen n-dimensionalen Datenpunkt, der mit einer variablen Parameter- liste von double - Werten erzeugt werden kann.
• Rectangle - Ein Rechteck, das mit zwei Objekten vom Typ Point2D erzeugt werden kann.
• Volume - Ein Volume kann durch zwei n-dimensionale Punkte erzeugt werden, die ein recht-
winkliges Volumen aufspannen, dessen Kanten alle achsenparallel verlaufen.
1
Implementieren Sie in allen Geometry - Typen das Interface Comparable mit der Me- thode compareTo(Object o). Diese soll zwei Instanzen vom Typ Geometry immer an- hand ihres Volumens miteinander vergleichen. Bei der Implementierung können Sie die War- nung des Compilers Comparable is a raw type. References to generic type Comparable should be parameterizedignorieren.
Ordnen Sie diese Klassen in der Vererbungshierarchie möglichst geschickt an, um sich unnötige Ar- beit zu ersparen. Achten Sie immer auf Information Hiding und machen Sie so wenige Datenfelder und Methoden wie möglich sichtbar. Sorgen Sie dafür, dass keine inkonsistenten Instanzen entstehen können.
Schreiben Sie außerdem eine separate Testklasse, die automatisch jede der implementierten Funktio- nen testet.
Hinweis
Sie können sich viel Arbeit ersparen, in dem Sie erst überlegen, wie der eindimensionale Fall aussieht und diesen dann auf n Dimensionen übertragen.

Ich verstehe nicht was ich mit der jar Datei machen soll? Soll ich die Datei in das Projekt einbinden??

Ja.

Genau, du bindest die JAR Datei ein und entwickelst dann vier neue Klassen (Point2D, Point, Rectangle und Volume) die von Geometry erben.

über Projekt->properties->java build path->add external jar?

Ja.

aha^^

Dann werde ich das mal versuchen danke

Für Hausaufgaben hier besser geeignet.
Auch für zukünftige Themen bitte das richtige Forum wählen.

Danke

So ist zwar schon eine Weile her aber hier ist der Initialentwurf…

/**
 * Erweiterung der Geometry Klasse um das Interface <code>Comparable</code>.
 * 
 *
 */
public abstract class ComparableGeometry extends Geometry implements Comparable {
    
	public ComparableGeometry(int dimensions) {
		super(dimensions);
	}
	
	
	public int compareto(Object o) {
		if(o instanceof Geometry) {
			return(int) ((this.volume() - ((Geometry) o).volume() ));
		} else {
			throw new RuntimeException("man kann nur Geometrie-Objekte vergleichen");
		}
	}
	
	
	public Geometry encapsulate(Geometry other) {
		
		if(this.dimensions() != other.dimensions()) {
			return null;
		}
		
		
		if(this.dimensions() == 2) {
			
			other.
			
			return new Rectangle()
		}
		
		
		
	}
	
	
	
	

}
/**
 * repräsentiert einen Punkt im n-dimensionalen Raum.
 * 
 * 
 * 
 *
 */
public class Point extends ComparableGeometry {
	
	/**
	 * enthält die Koordinaten des Punkts.
	 */
	private double[] koords;
	
	
	
	public Point(double... koords) {
		super(koords.length);
		this.koords = new double[koords.length];
		
		for(int i=0; i < koords.length; i++) {
			this.koords** = koords**;
		}
		
	}
	
	
	
	
	

	@Override
	public int compareTo(Object o) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	//public Geometry encapsulate(Geometry other) {
	
		//if(this.dimensions() != other.dimensions()) {
			//return null;
		//}
		
	
	public String toString() {
		StringBuffer buf = new StringBuffer(); buf.append("(");
		for (int dim = 0; dim < this.dimensions(); dim++) {
		buf.append(koords[dim] + ((dim < this.dimensions() - 1) ? "," : "")); }
		   buf.append(")");
		return buf.toString(); }
	
	
	
	
		
		
		
		
		
		
		
		
		
	
    
	/**
	 * die Methode liefert das Volumen des Objekts zurück(das Volumen eines Punkts ist 0.)
	 */
	@Override
	public double volume() {
		
		return 0;
	}
	
	
	public double getDimValue(int dim) {
		
		return koords[dim];
	}

}
/**
 * die Darstellung eines 2 dimensionalen Punkts.
 * 
 *
 */
public class Point2D extends Point {
	
	/**
	 * Ausnutzung der Elternklasse als Spezialfall dieser.
	 * @param x
	 *         x-Koordinate.
	 * @param y
	 *         y-Koordinate.
	 */
	public Point2D(double x, double y) {
		super(x,y);
	}

}




/**
 * Repräsentiert ein Rechteck im 2-dimensionalen Raum.
 * 
 * 
 *
 */
public class Rectangle extends ComparableGeometry {
    
	
	private Point2D anf_point;
	
	
	private Point2D end_point;
	
	
	public Rectangle(Point2D anf, Point2D end) {
		super(2);
		
		
	}
	
	
	
	@Override
	public int compareTo(Object o) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Geometry encapsulate(Geometry arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public double volume() {
		// TODO Auto-generated method stub
		return 0;
	}

}

public class Volume extends ComparableGeometry {
    
	
	private Point start;
	
	private Point end;
	
	
	
	public Volume(Point start, Point end) {
		super(start.dimensions());
		
		if(start.dimensions() != end.dimensions()) {
			throw new RuntimeException("Punkte haben verschiedene Dimensionszahl");
		}
		
		this.start = start;
		this.end = end;
		
	}
	
	
	
	
	
	
	@Override
	public int compareTo(Object o) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Geometry encapsulate(Geometry arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public double volume() {
		int vol = 1;
		
		for(int i= 0; i< start.dimensions() ; i++) {
	       vol *= length(i);		
		}
		
		return 0;
	}
	
	
	
	private double length(int dim) {
		
		
		
		return Math.abs(end.getDimValue(dim) - start.getDimValue(dim));
	}

}

Ich habe Probleme die encapsulate Methode zu implementieren und wie ich sie in meiner Klassehirachie verteilen soll.
Und ich verliere ein bisschen den Überblick… (was fehlt noch usw.)

[OT]

Implementieren Sie in allen Geometry - Typen das Interface Comparable mit der Me- thode compareTo(Object o). Diese soll zwei Instanzen vom Typ Geometry immer an- hand ihres Volumens miteinander vergleichen. Bei der Implementierung können Sie die War- nung des Compilers Comparable is a raw type. References to generic type Comparable should be parameterizedignorieren

Ehrlich?

Kann man zwar machen, aber warum nicht gleich richtig?

//bzw.
public abstract class ComparableGeometry extends Geometry implements Comparable<? extends Geometry> {
//bzw.
public abstract class ComparableGeometry extends Geometry implements Comparable<? extends ComparableGeometry> {```



```return(int) ((this.volume() - ((Geometry) o).volume() ));

//kann man auch damit ausdrücken

return Double.compare(this.volume(), ((Geometry) o).volume());```[/OT]


In den Klasse Point, Rectangle und Volume wird die compareTo-Methode überschrieben. Das sollte man nicht tun, da die Superklasse ComparableGeometry bereits eine korrekte Implementierung, welche das Volumen heranzieht und vergleicht. Durch das Überschreiben wird die Implementierung der Superklasse nutzlos, da überschrieben.


Zudem kann man Überlegungen zu einer besseren Vererbungshirarchie anstellen

`Point2D extends Point` ist ok

`Rectangle extends Volume` ist zu Überlegen.

Damit ist diese Implementierung von Rectangle ausreichend.

```public class Rectangle extends Volume {
  public Rectangle(Point2D a, Point2D b) {
    super(a,b);
  }
}```

Allerdings fehlt bisher die Berechnung des Volumens für Rectangle und Volume.

Dafür müsste man entweder auf die Werte der koordinaten der Punkte zugreifen können oder die Berechnung in Point erledigen.

in Point

```public double volumeBetween(Point p) {
  if(this.dimension() != p.dimension()) {
    throw new RE("different dimensions");
  } else {
    double result = 1.0;
    for(int i = 0; i < koords.length; i++) {
      result *= Math.abs(p.koords** - this.koords**);
    }
    return result;
  }
}```

In Volume dann z.B.

```public double volume() {  return a.volumeBetween(b); }```


Nun zur fehlenden encapsulate-Methode:

Dafür würde ich in Point eine min und eine max-Methode erstellen.

```public Point min(Point p) {
  if(this.dimension() != p.dimension()) {
    throw new RE("different dimensions");
  } else {
    double[] result = new double[koords.length]
    for(int i = 0; i < koords.length; i++) {
      result**= (p.koords** < this.koords**)? p.koords**: this.koords**;
    }
    return new Point(result);
  }
}

public Point max(Point p) {
  if(this.dimension() != p.dimension()) {
    throw new RE("different dimensions");
  } else {
    double[] result = new double[koords.length]
    for(int i = 0; i < koords.length; i++) {
      result**= (p.koords** > this.koords**)? p.koords**: this.koords**;
    }
    return new Point(result);
  }
}

Und in Volume später:

public Geometry encapsulate(Geometry other) {
  //Check dimensions, eventually return null;
  Point thisMin = a.min(b);
  Point thisMax = a.max(b);
  Point otherMin = other.a.min(other.b);
  Point otherMax = other.a.max(other.b);

  return new Geometry(thisMin.min(otherMin), thisMax.max(otherMax));
}

(EDIT: Ja, war zu langsam :rolleyes: )

Die encapsulate-Methode wird nicht in der abstrakten ComparableGeometry erstellt werden können. Der Typ der Geometrie, die zurückgegeben werden soll, hängt ja vom Typ ab, auf dem diese Methode aufgerufen wird. Also, wenn man
Geometry result = rectangle.encapsulte(point);
aufruft, soll das Ergebnis ja wieder ein Rectangle sein (zumindest interpretiere ich das so…). Es muss also in jeder konkreten Klasse so eine Methode geben.

Ansonsten gibt’s viele Details, die man verbessern (oder zumindest hinterfragen) könnte.

(BTW: Point2D extends Point, Rectangle extends .... - da könnte man was anderes hinschreiben, auch wenn man sich genau überlegen müßte, ob da Mrs. Liskov was dagegen haben könnte)

Oh ja, da ist noch was, aber wenn man sich nicht um Generics kümmert, dann kann man darüber auch hinwegsehen.

Eigentlich sogar

Point2D extends Point

Rectangle extends Volume

und, UND, UND

Point extends Volume, wobei Anfangs und Endpunkt für den Fall von Point identisch sind.

Wenn das ganze dann noch kompiliert, bzgl der zyklischen Abhängigkeiten.

Ist eigentlich super(this, this) in einem Konstruktor möglich?

Da

Ordnen Sie diese Klassen in der Vererbungshierarchie möglichst geschickt an, um sich unnötige Ar- beit zu ersparen. Achten Sie immer auf Information Hiding und machen Sie so wenige Datenfelder und Methoden wie möglich sichtbar.

Den Kram von ComparableVolume kann man nach Volume verschieben, da davon alles direkt oder indirekt erbt.

Ja, auf das „Rectangle extends Volume“ wollte ich hinaus (wollte nur nicht alles vorkauen ;-))

Das mit der Generics-Warnung ist mir auch aufgefallen. In so einem Fall KÖNNTE man das wohl noch rechtfertigen: Diese Selbstreferentiellen Generics sind ein Graus, und dass man, wenn man die Grundlagen von OOP erläutern will, sowas wie
public abstract class ComparableGeometry extends Geometry implements Comparable<? extends ComparableGeometry>
vermeiden will, ist verständlich. Das krankt (genau wie der Rückgabetyp von „encapsulate“) IMHO einzig und allein daran, dass es keinen „ThisType“ gibt:

abstract class ComparableGeometry implements Comparable<""ThisType""> {
...

    abstract ""ThisType"" encapsulate(Geometry other);
}

Aber das wird schon seinen Grund haben.

Mal ganz abgesehen davon: Ich bin kein Fan von „Comparable“. In den ALLERmeisten Fällen ist es besser, NICHT Comparable zu implementieren, sondern einen Comparator zu verwenden. „Comparable“ sollte für die Fälle vorbehalten bleiben, wo wirklich eine eindeutige, unzweifelhafte natürliche Ordnung existiert (und das ist selten der Fall).

Aber wie gesagt, bei solchen Lern-Aufgaben muss man Abstriche machen, und hoffen, dass die wichtigen, zu vermittelnden Punkte rüberkommen, und unbedeutende Details (wie alles, was ich in dieser Antwort erwähnt habe ;-)) nicht vom Kern ablenken :wink:

danke für die ausführlichen Antworten, ich habe die Aufgabe allerdings abgebrochen, weil es nur 1 von 7 war und ich bei der encapsulate einfach nicht weiterkommen bin.

ich werde die Musterlösung nochmal posten, sobald sie on ist.

[OT][quote=Marco13]“Comparable” sollte für die Fälle vorbehalten bleiben, wo wirklich eine eindeutige, unzweifelhafte natürliche Ordnung existiert (und das ist selten der Fall).[/quote]

und hier?[/OT]

[QUOTE=mymaksimus][OT]

und hier?[/OT][/QUOTE]

Comparable und Comparatoren verwendet man zum sortieren.

Hier ist die Sortierung schon fraglich, da 2D und 3D auf eine Zahl projiziert wird mit der verglichen wird.


new Volume(new Point(0,0,0), new Point(1,1,0)).volume() == 0```


Beides mal das selbe Objekt, im 2-Dimensionalen ist die Fläche größer, als der Raum im 3 Dimensionalen.


Ein Comparator hat den Vorteil, dass man die Sortierung austauschen kann, wenn man daran Bedarf hat. 
Wenn man nun mehrere Comparatoren zur Auswahl hat, wie kann man sich dann entscheiden, welche die einzig Wahre durch Comparable zu implementierende ist?


Die Distanz zwischen den beiden Punkten könnte man z.B. auch heranziehen. Diese ist bei beiden Objekten sqrt(2). Hier hat man wenigstens die gleiche Einheit zum Vergleichen.

Unter diesem Link ist die Musterlösung zu finden(Aufgabe 4.1)

http://www-lehre.inf.uos.de/~binf/2015/uebung/blatt04/blatt04.pdf

Ich würde das Thema gerne nochmal aufwärmen, da ich dieses Jahr den gleichen Kurs belege. Ich verstehe in dem Code von MrEuler nicht so ganz woher das “a” bzw. “b” herkommt. Und könnte jemand vielleicht erläutern wie die methode “volumeBetween(point p)” funktioniert?

Ich habe bei meinem Programm bis jetzt nur die ComparableGeometry und Point bzw. Point2D, wobei ich mir bei letzterem nicht wirklich sicher bin.

Die Aufgabenstellung ist dieses Jahr exakt die gleiche.

Werd’ mal spezifischer. Ich sehe beim Überfliegen “a” und “b” jetzt erstmal nur als Konstruktorparameter

Okay,entschuldige, dass ich so unspezifisch frage mag daran liegen dass ich die Aufgabe nicht ganz verstehe.

Der Thread Ersteller Bisaflor hat ja im Prinzip im Konstruktor für ein Volume nur gesagt, dass wir einen “Point Start” und einen “Point End” haben ,
diese beiden Punkte stellen jetzt also ein “Volume” dar? Mir ist an der Stelle bereits nicht klar, inwiefiern dadurch ein “Volume” definiert ist.

würdest du denn verstehen wie ein Viereck von 4 Eckpunkten beschrieben wird?
irgendwo muss ja das menschliche Verständnis anfangen, wie will man da noch weiter erklären?

zwei Punke definieren einen Raum (oder etwas in anderen Dimensionen), das ist hier eben so,
liest die Aufgabe für die Sonderbedingungen die dies ermöglichen

dass eine Linie in 2 Punkten beschrieben ist erscheint zunächst noch leicht,
wobei das hier 1D-Raum wäre, jeder Punkt nur eine Koordinate, von 4 bis 6 etwa, eher ungewöhnlich,

von einem Rechteck 2 Punkte, unten links + oben rechts, Rest wird als gerade Linien angenommen, so wie es ja in der Aufgabe steht

von einem Quader 2 Punkte, unten links vorne + oben rechts hinten,
Beispiele aufmalen und verstehen, vorher geht gar nichts,


volumeBetween() arbeitet darauf,
ein Punkt als Parameter, der andere das this-Objekt, Methode wird an einem Punkt aufgerufen,

zwei Punkte definieren ja ein Objekt und so wie man sich das denkt rechnet man es dann auch aus,

schau dir deine Beispiele an, von Rechteck/ Quader, berechne die Fläche auf welche Weise auch immer,
und schaue exakt nach was das Programm (bei korrekten Eingaben) Schritt für Schritt rechnet,
dann müsstest du idealerweise Zwischenwerte wiederfinden, von gleichen Endergebnis ganz zu schweigen, ist ja auch nur simple Sache