Vererben von Singleton

usrr

Bekanntes Mitglied
Hallo,

ich habe eine Basisklasse Modul, die vererbt werden kann. Alle abgeleiteten Modul-Klassen, sollen nur einmal existieren können, also Singeltons sein. Ich möchte diesen Mechanismus aber nur in der Basisklasse implementieren:

Java:
public class Module  {

	private static Module instance;

	private Module() {
	}
	
	public static BaseModule getInstance() {
		if ( instance == null ) {
			instance = new Module();
		}
		return instance;
	}
}

Erstens werden die statischen Elemente nicht vererbt und selbst wenn, dann hätte "instance" immer den Type Module und nicht AbcModule.

Gibt es dafür eine Lösung?
 
Klingt doch gut, wozu dann diese Idee mit den vererbaren Singletons?

Einfach nur um ein "Design Pattern" einzusetzen? 😉
 
Eine Alternative wäre es gewesen, die Funktionalität statisch zu implementieren. Das hääte bei den meisten Modulen auch funktioniert. Allerdings habe ich mir als Ziel gestezt, (und das tatsächlich um zu lernen) dass Module bzw. Funktionalität später hinzugefügt werden soll, ohne die Hauptklasse ändern zu müssen.

Das Singelton ist nicht 100% notwenig, weil ich ja drauf achten könnte Module nicht doppelt zu benutzen. Aber trotzdem will ich sehen was machbar ist.

Fazit: Ja, im Prinzip einfach um es auszuprobieren.
 
Tipp: Vergiss Singleton ganz schnell wieder.

Macht man in der Realtität sehr selten, und niemals vererbar 😉

Wen du was relevantes probieren möchtest, versuchs doch mal mit Google Guice.
 
Falls die Module keine Abhängigkeiten haben könntest du folgendes versuchen:

Java:
public abstract class Module  {
 
    private static Map<Class<? extends Module>, Module> instances = new HashMap<>();
 
    public static <T extends Module> T getInstance(Class<T> clazz) {
        if (!instances.containsKey(clazz)) {
        	try {
        		T instance = clazz.newInstance();
        		
        		instances.put(clazz, instance);
        	} catch (InstantiationException | IllegalAccessException ex) {
        		ex.printStackTrace();
        	}
        }
        
        return clazz.cast(instances.get(clazz));
    }
    
    public static void main(String[] args) {
		ModuleA moduleA = Module.getInstance(ModuleA.class);
		System.out.println(moduleA);
	}
}

class ModuleA extends Module {}

class ModuleB extends Module {}
Falls dir als Typ Module ausreicht und du nicht den konkreten Typ brauchst, kannst du auf den Cast mit dem Class Objekt auch verzichten.

Aber naja, das ist schon sehr wirr.
 
Evtl. gibt es noch andere Möglichkeiten. Z.B,. hatte ich überlegt, den Konstruktor auf protected zu setzen und die Module ins gleiche Verzeichnis, wie den Verwalter zu speichern. Allerdings dürfte das der Übersicht nicht gerade dienen 🙂. Auch bräcuhte man später bei Erweiterungen Zugriff auf das entsprechende Verzeichnis.

Möglich wäre aber auch in den Verwalter eine Factory einzubauen, die die Module auf verlangen erzeugt. Dort könnte dann geprüft werden, ob schon eine Instanz existiert. Aber die Module wären dann, auch nicht geschützt, so dass eigentlich nichts gewonnen wurde.
 
@EikeB

Kannst du mir bitte verraten was diese Zeile macht, was es damit auf sich hat? Hat das was mit Templates zu tun so wie es sie in C++ gibt?

Java:
private static Map<Class<? extends Module>, Module> instances = new HashMap<>();

Danke für eine kurze Erläuterung, ich kann nicht wirklich was damit anfangen.
 
Dann musst du zwei Sachen ändern:

Java:
private static Map<Class<? extends Module>, Module> instances = new HashMap<>();
=>
Java:
private static Map<Class<? extends Module>, Module> instances = new HashMap<Class<? extends Module>, Module>();

Java:
} catch (InstantiationException | IllegalAccessException ex) {
  ex.printStackTrace();
}
=>
Java:
} catch (InstantiationException ie) {
  ie.printStackTrace();
} catch (IllegalAccessException iae) {
  iae.printStackTrace();
}

Das erste nennt sich diamond operator und spart einem das doppelte hinschreiben der generics. Mit dem zweiten kann man mehrere exceptions catchen und spart sich das doppelte
Code:
printStackTrace()
.
 
Hier könnte man eigentlich schon wieder 'ne Grundsatzdiskussion anzetteln, aber das ist nicht meine Intention. 😉
Dein Vorhaben ist mit Singletons nicht durchführbar, das Pattern, dass du suchst muss anders heissen. Singletons sind Klassen, die sich nur einmal instanzieren lassen (sollten). Das impliziert, dass sie im Grunde genommen finale Klassen sind, auch wenn sie nicht als solche deklariert wurden. Das bedeutet aber nicht, dass Singletons keine anderen Klassen erweitern können, an dieser Stelle nenne ich gern das Beispiel Service. Davon gibt es bekanntlich viele, aber pro Port halt nur einen. Das Beispiel hinkt evtl. an der Tatsache, dass es auch multiinstanzfähige Dienste gibt, aber das wären dann auch keine Singletons mehr. Das Singleton wird viel zu oft mit anderen verwechselt und so kommt es dann zu diesen Grundsatzdiskussionen. Das ist auch kein Anti-Pattern, sondern man muss wissen, wann man eines benötigt. Gründe für die Wahl des Singleton-Pattern sind allerdings so rar geworden, dass man schon zu hinkenden Beispielen greifen muss, weil einem selber keiner mehr einfällt, wenn man's erklären will.
Eine Möglichkeit für dich wäre also deine Klasse Modul abstrakt zu machen und erst die konkreten Klassen zu "Singletons". Das wäre dann eine Art Factory-Pattern, würd' ich sagen.
 
Zuletzt bearbeitet von einem Moderator:
Das bringt mich wieder an die Stelle, die mich schon etwas länger beschäftigt.

Das Module hat einen Konstructor Modul(Owner owner). Obwohl ich in den abgeleiteten Modulen nichts am Konstructor ändere, muss ich jedesmal einen neuen angeben, der über super() den alten Aufruft. Setzte ich den Konstruktor jetzt auf private, geht das nicht mehr und ich muss einen Default-Konstruktor anlegen, was ich eigentlich nicht will.
 
Dann setz' den Konstruktor genau in die Mitte von public und private, sprich auf protected. Die Klasse Modul deklarierst du noch als abstrakt und schon lässt sie sich nur noch von Kind-Klassen instanzieren.
 

Zurück
Oben