Vorneweg schonmal: ::manklatsch für die (Eigen)Initiative!
Hab’s noch nicht getestet, nur mal kurz über den Code drübergeschaut. Da könnte man natürlich 1000 Sachen hinterfragen oder kritisieren. Mehr oder weniger „wichtige“ Dinge.
Was mir aufgefallen ist, ist die Verwendung von „Vector“. Das ist üblicherweise zu speziell. Ein „Vector“ ist eigentlich nur eine (synchronisierte) Implementierung des „List“-Interfaces. Also statt sowas wie
Vector<Point> points = new Vector<Point>();
sollte man i.a. eher schreiben
List<Point> points = new Vector<Point>();
Aber auch DAS (wenn überhaupt) nur, wenn man eine synchronisierte Liste braucht. Meistens sollte es eine
List<Point> points = new ArrayList<Point>();
schon tun.
(NB: Das „synchronisiert“ bedeutet, grob gesagt, dass man „Vector“ mit mehreren Threads verwenden kann. Darüber solltest du dir auch mal Gedanken machen, aber das hier auszubreiten würde wohl zu weit führen…)
Insbesondere sollte in Methodensignaturen praktisch NIE das Wort „Vector“ oder „ArrayList“ auftauchen. Man sollte immer das Interface verwenden, das die minimale Menge von Operationen anbietet, die man braucht, um das machen zu können, was man will. Das nennt man manchmal „Gegen das Interface programmieren“.
Als Beispiele: So eine Methode sieht erstmal OK aus:
void computeSum(ArrayList<Point> points) {
Point result = new Point();
for (Point point : points) result.add(point);
return result;
}
Man kann sie aufrufen mit
ArrayList<Point> points = ...;
Point sum = computeSum(points);
Aber man kann sie NICHT aufrufen mit
LinkedList<Point> points = ...;
Point sum = computeSum(points);
(Weil ja eine ArrayList erwartet wird, und keine LinkedList!)
Wenn man das verallgemeinert zu
void computeSum(List<Point> points) { // List statt ArrayList
...
}
Dann kann man auch eine LinkedList übergeben.
Aber NOCH allgemeiner wäre sowas wie
void computeSum(Collection<Point> points) { // Collection statt List
...
}
Dann kann man nicht nur eine ArrayList oder LinkedList übergeben, sondern auch eine HashSet oder so.
Tatsächlich würde in diesem Fall sogar das hier reichen:
void computeSum(Iterable<Point> points) { // Iterable statt Collection
...
}
Weil man in der Methode ja nichts anderes macht, als über alle Punkte drüberzuiterieren. Und dazu braucht man NUR das „Iterable“-Interface.
Und NOCH einen Tick allgemeiner:
void computeSum(Iterable<? extends Point> points) { // "? extends Point" statt "Point"
...
}
Das hat den Vorteil, dass man dort auch Dinge übergeben kann, die eine Unterklasse von „Point“ sind. Um’s zu verdeutlichen:
List<MySpecialPoint> points = ...; // Wobei "MySpecialPoint extends Point" gilt
Point sum = computeSum(points); // Das geht nur, wenn man "? extends Point" verwendet hat!
Die letzte Methodensignatur ist also das allgemeinst-mögliche für diesen Fall: Man braucht etwas, wo man sich nacheinander Dinge abholen kann, die mindestens „Point“ sind.
Du scheinst dort an einigen Stellen das „Visitor“-Pattern zu verwenden. Wie und wo und warum hat sich mir beim schnellen Drüberhschauen nicht ganz erschlossen. Es sieht erstmal seltsam aus, KANN aber OK sein (da kann ich gerade nichts dazu sagen…)
Zum Clusterable
Interface: Jaa… In der Apache Math Library gibt es auch Clustering-Algorithmen. Dort gab es in Version 3.0 auch dieses Interface Clusterable
:
https://commons.apache.org/proper/commons-math/javadocs/api-3.0/org/apache/commons/math3/stat/clustering/Clusterable.html
Als ich das gesehen habe, habe ich mir gedacht: " :eek: Welcher IDOT. hat sich denn diesen MST ausgedacht!! :suspect: "
Warum? Ganz einfach: Wenn man 1000000 Datenobjekte hat, und die Clustern will, dann muss man für jedes einzelne dieser Datenobjekte ein passendes Objekt einer Klasse erstellen, die dieses Clusterable
-Interface implementiert. Ein Krampf. Oder auch: FAIL.
In Version 3.3 der Apache Math Library wurde das Interface dann „Deprecated“, und durch ein neues Clusterable
-Interface ersetzt:
ALT: http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/stat/clustering/Clusterable.html
NEU: http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/ml/clustering/Clusterable.html
Auch das neue ist in mancher Hinsicht fragwürdig, aber zumindest besser als vorher…
Insgesamt könnte man in die theoretische Planung und Strukturierung so eines Programms/so einer Bibliothek SEHR viel (geradezu beliebig viel!) Arbeit stecken. Aber dazu muss man sich mit den Clusteringverfahren und ihren Eigenheiten und Anforderungen schon sehr gut auskennen. Wenn dann noch Streaming, Fuzzy-Clustering oder Out-Of-Memory-Ansätze dazukommen, wird das schnell kompliziert.
BTW: Das Buch sieht ganz interessant aus (da werd’ ich ggf. mal über das eine oder andere Kapitel drüberschauen, wenn ich Zeit habe).