Es ist unmöglich, eine abstrakte Klasse zu instanziieren. Was man wirklich tun kann, ist, einige allgemeine Methoden in einer abstrakten Klasse zu implementieren und andere unimplementiert zu lassen (indem man sie als abstrakt deklariert) und sie von den konkreten Nachfolgern je nach Bedarf implementieren zu lassen. Dann kann man eine Fabrik erstellen, die eine Instanz dieser abstrakten Klasse (eigentlich ihren Implementierer) zurückgibt. In der Fabrik entscheiden Sie dann, welchen Implementierer Sie wählen. Dies ist als Factory Design Pattern bekannt:
public abstract class AbstractGridManager {
private LifecicleAlgorithmIntrface lifecicleAlgorithm;
// ... more private fields
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
//Methods common to all implementors
public Grid calculateNextLifecicle(Grid grid){
return this.getLifecicleAlgorithm().calculateNextLifecicle(grid);
}
public LifecicleAlgorithmIntrface getLifecicleAlgorithm() {
return lifecicleAlgorithm;
}
public void setLifecicleAlgorithm(LifecicleAlgorithmIntrface lifecicleAlgorithm) {
this.lifecicleAlgorithm = lifecicleAlgorithm;
}
// ... more common logic and getters-setters pairs
}
Der konkrete Implementierer muss nur die als abstrakt deklarierten Methoden implementieren, hat aber Zugriff auf die Logik, die in den nicht als abstrakt deklarierten Klassen in einer abstrakten Klasse implementiert ist:
public class FileInputGridManager extends AbstractGridManager {
private String filePath;
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
public class FileInputGridManager extends AbstractGridManager {
private String filePath;
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
public Grid initGrid(String filePath) {
List<Cell> cells = new ArrayList<>();
char[] chars;
File file = new File(filePath); // for example foo.txt
// ... more logic
return grid;
}
}
Dann sieht das Werk schließlich so aus:
public class GridManagerFactory {
public static AbstractGridManager getGridManager(LifecicleAlgorithmIntrface lifecicleAlgorithm, String... args){
AbstractGridManager manager = null;
// input from the command line
if(args.length == 2){
CommandLineGridManager clManager = new CommandLineGridManager();
clManager.setWidth(Integer.parseInt(args[0]));
clManager.setHeight(Integer.parseInt(args[1]));
// possibly more configuration logic
...
manager = clManager;
}
// input from the file
else if(args.length == 1){
FileInputGridManager fiManager = new FileInputGridManager();
fiManager.setFilePath(args[0]);
// possibly more method calls from abstract class
...
manager = fiManager ;
}
//... more possible concrete implementors
else{
manager = new CommandLineGridManager();
}
manager.setLifecicleAlgorithm(lifecicleAlgorithm);
return manager;
}
}
Der Empfänger von AbstractGridManager würde die Methoden von AbstractGridManager aufrufen und die Logik erhalten, die im konkreten Deszendenten (und teilweise in den Methoden der abstrakten Klasse) implementiert ist, ohne zu wissen, was die konkrete Implementierung ist, die er erhält. Dies wird auch als Inversion der Kontrolle oder Dependency Injection bezeichnet.