Ich habe eine Menge von Methoden, die in eine Klasse gekapselt sind, denn man kann ja in Java keine Funktionen als Parameter nehmen.
Jetzt möchte ich den Benutzer aber auswählen lassen, welche Methode er nehmen will. Allerdings möchte ich das nicht hardcoden, da ja später Methoden dazukommen könnten.
Hier mal ein einfaches Beispiel:
Jetzt soll der Benutzer angezeigt bekommen, welche Methoden es alles gibt, und zwar ungefähr so (pseudocode):
Problem dabei ist jetzt erstens, dass es sowas wie "implementingClassesOf" nicht gibt und zweitens, dass man keine statischen Methoden von Klassen aufrufen kann. Das finde ich jedoch unlogisch. Wenn ich String.valueOf() mache, brauche ich ja kein Objekt, sondern nur eine Klasse und "String" ist ja eine Klasse. Deshalb müsste doch "String.getClass()" eigentlich das gleiche sein, wie "String", aber da es das nicht ist, kann mir jemand erklären, warum?
Alternative:
Um das zu umgehen, habe ich mir folgendes überlegt:
Jetzt könnte man folgendes schreiben:
Das hat jedoch folgende Nachteile:
- man braucht eine zusätzliche Klasse (hier "Algorithms")
- dort müssen die Klassen manuell eingetragen werden, also jedesmal ein Eintrag hinzugefügt werden, wenn eine neue Unterklasse dazu kommt
- es wird eine statische Methode von einem Objekt aufgerufen, durch Vererbung kann da also auch die falsche aufgerufen werden
- es kann ein Overhead durch Konstruktorinitialisierung entstehen. Nehmen wir an, es dauert 1 Minute die Klasse "HyperdimensionaleAddition" zu initialisieren, wobei gar nicht garantiert ist, dass diese auch benutzt wird
- bei jedem Aufruf eines Algorithmus kann ein neues Ergebnis herauskommen, wenn durch die vorhergehenden Aufrufe Felder der Instanz modifiziert wurden
- der Algorithmus kann in einen ungültigen Zustand kommen und nicht mehr funktionieren, dann kann die Methode nicht mehr aufgerufen werden (das würde umgangen werden, wenn jedes mal eine neue Instanz erzeugt wird)
Die letzten beiden Punkte kann man natürlich durch sorgfältige Programmierung vermeiden. Das Argument des Overheads kann auch gegen eine Neuinitialisierung verwendet werden, weil dann zwar nicht alle möglichen Algorithmen im vorraus initialisiert werden würden, aber dafür ein Algorithmus mehrmals initialisiert wird. Das Problem mit der statischen Methode kann man beheben, indem man sie einfach nicht statisch macht.
Trotzdem bin ich mir noch nicht sicher, ob diese Alternative das Beste in dieser Situation ist und würde deshalb gerne wissen, was denn das Standardverfahren für diese Art Problem ist.
Jetzt möchte ich den Benutzer aber auswählen lassen, welche Methode er nehmen will. Allerdings möchte ich das nicht hardcoden, da ja später Methoden dazukommen könnten.
Hier mal ein einfaches Beispiel:
Java:
public interface Algorithm
{
public static String getDescription();
public int exec(int param1, int param2);
}
public class Addition implements Algorithm
{
@Override
public static String getDescription() {return "Addition";}
@Override
public int exec(int param1, int param2) {return param1+param2;}
}
Java:
System.out.println("Which algorithm do you want to use?");
for(Class<Algorithm> algorithmClass: implementingClassesOf(Algorithm) )
{
System.out.println(algorithmClass.getDescription());
boolean useThis = input.nextBoolean();
if(useThis)
{
new algorithmClass().exec(param1, param2);
}
}
Problem dabei ist jetzt erstens, dass es sowas wie "implementingClassesOf" nicht gibt und zweitens, dass man keine statischen Methoden von Klassen aufrufen kann. Das finde ich jedoch unlogisch. Wenn ich String.valueOf() mache, brauche ich ja kein Objekt, sondern nur eine Klasse und "String" ist ja eine Klasse. Deshalb müsste doch "String.getClass()" eigentlich das gleiche sein, wie "String", aber da es das nicht ist, kann mir jemand erklären, warum?
Alternative:
Um das zu umgehen, habe ich mir folgendes überlegt:
Java:
public class Algorithms()
{
public static final Algorithm[] algorithms = {new Addition(), new Subtraktion()};
}
Jetzt könnte man folgendes schreiben:
Java:
System.out.println("Which algorithm do you want to use?");
for(Algorithm algorithm: Algorithms.algorithms )
{
System.out.println(algorithm.getDescription());
boolean useThis = input.nextBoolean();
if(useThis)
{
algorithm.exec(param1, param2);
}
}
Das hat jedoch folgende Nachteile:
- man braucht eine zusätzliche Klasse (hier "Algorithms")
- dort müssen die Klassen manuell eingetragen werden, also jedesmal ein Eintrag hinzugefügt werden, wenn eine neue Unterklasse dazu kommt
- es wird eine statische Methode von einem Objekt aufgerufen, durch Vererbung kann da also auch die falsche aufgerufen werden
- es kann ein Overhead durch Konstruktorinitialisierung entstehen. Nehmen wir an, es dauert 1 Minute die Klasse "HyperdimensionaleAddition" zu initialisieren, wobei gar nicht garantiert ist, dass diese auch benutzt wird
- bei jedem Aufruf eines Algorithmus kann ein neues Ergebnis herauskommen, wenn durch die vorhergehenden Aufrufe Felder der Instanz modifiziert wurden
- der Algorithmus kann in einen ungültigen Zustand kommen und nicht mehr funktionieren, dann kann die Methode nicht mehr aufgerufen werden (das würde umgangen werden, wenn jedes mal eine neue Instanz erzeugt wird)
Die letzten beiden Punkte kann man natürlich durch sorgfältige Programmierung vermeiden. Das Argument des Overheads kann auch gegen eine Neuinitialisierung verwendet werden, weil dann zwar nicht alle möglichen Algorithmen im vorraus initialisiert werden würden, aber dafür ein Algorithmus mehrmals initialisiert wird. Das Problem mit der statischen Methode kann man beheben, indem man sie einfach nicht statisch macht.
Trotzdem bin ich mir noch nicht sicher, ob diese Alternative das Beste in dieser Situation ist und würde deshalb gerne wissen, was denn das Standardverfahren für diese Art Problem ist.