Du bist nicht angemeldet.

Werbeanzeige

1

02.01.2015, 21:13

Singletons für Ressourcen-Manager

Hallo liebe Community,

nachdem ich heute schon im WTF-Codeschnipsel-Thread einen durchaus merkwürdigen Codeschnipsel gepostet hatte, und daraufhin auch auf "Evil Singletons" hingewiesen worden bin, mache ich mir gerade Gedanken bzgl. meines Ressourcen-Verwaltungssystems. Ähnlich dem, der OGRE-Engine, ist mein System derzeit folgendermaßen organisiert:

Für jeden Ressourcentyp gibt es einen Manager, welcher ein Singleton ist. Dieser ist für die Verwaltung aller Ressourcen dieses Typs zuständig. Meine Frage momentan ist, ob es eigentlich legal ist, solche Manager als Singletons zu implementieren, bzw. wie man das schöner umgehen könnte. In Code sieht das dann etwa so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class ResourceManager {

    public:

        typedef std::map<String, ResourcePtr> ResourceMap;
        typedef ResourceMap::iterator ResourceMapIterator;
        typedef std::map<ResourceID, ResourcePtr> ResourceIDMap;
        typedef ResourceIDMap::iterator ResourceIDMapIterator;

        ResourceManager ();
        virtual ~ResourceManager ();

        void declareResource ( const String& name );
        bool declareResourceXML ( const char* file );

        ResourcePtr getResourceByName ( const String& name );
        ResourcePtr getResourceByID ( ResourceID uuid );
        ResourcePtr loadResourceByName ( const String& name );
        ResourcePtr loadResourceByID ( ResourceID uuid );

        void setResourceLoader ( ResourceLoader* loader );
        ResourceLoader* getResourceLoader ();

        bool hasResource ( ResourceID uuid );


    protected:

        virtual Resource* doInstantiateResource ( const String& name, ResourceID id ) = 0;

    private:

        static ResourceID kGlobalUniqueID;


        ResourceMap mResourceMap;
        ResourceIDMap mResourceIDMap;

        ResourceLoader* mResourceLoader;

    };


Beispiel für einen solchen Ressourcen-Manager:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MaterialManager : public ResourceManager, public ISingleton<MaterialManager> {

    public:

        MaterialManager ();
        virtual ~MaterialManager ();

        MaterialPtr getMaterialByName ( const String& name );
        MaterialPtr getMaterialByID ( ResourceID uuid );
        MaterialPtr loadMaterialByName ( const String& name );
        MaterialPtr loadMaterialByID ( ResourceID uuid );

    protected:

        virtual Resource* doInstantiateResource ( const String& name, ResourceID uuid );

    };


Habt ihr Verbessungsvorschläge bzgl. der Singletons, oder findet ihr, dass das so "normales" Code-Design ist? Über Kritik an dem System würde ich mich durchaus freuen :)

Liebe Grüße,
~ EuadeLuxe ~

BlueCobold

Community-Fossil

Beiträge: 10 890

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

02.01.2015, 21:15

Natürlich ist es legal. Es hat nur furchtbar viele Nachteile und keinen einzigen echten Vorteil.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

3

02.01.2015, 21:22

Gibt es denn Patterns, die sich für den Usecase von Ressourcen-Managern besser eignen? Ich bin mir nämlcih momentan unsicher, ob es besser wäre, überall einen Zeiger auf einen passenden Ressourcen-Manager zu übergeben. Meiner Ansicht nach - korrigiert mich bitte, wenn ich falsch liege - koppelt das Systeme doch erste recht aneinander, oder nicht?

BlueCobold

Community-Fossil

Beiträge: 10 890

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

4

02.01.2015, 21:30

Nö, macht es nicht. Du kannst jederzeit die übergebene Instanz durch eine Unterklasse ersetzen oder im Fall eines vernünftigen Interface-Designs oder Bridge-Patterns ist die Kopplung nur an das Interface gebunden, die Implementierung selbst kann jederzeit getauscht werden. Das geht bei einem Singleton nicht. Somit ist die Kopplung deutlich variabler ohne das Singleton.
Wieso glaubst Du denn, dass die Kopplung höher wäre? In beiden Fällen benutzen die Klassen ja den jeweiligen Manager, so oder so - im Singleton-Fall allerdings weniger offensichtlich, was allein schon negativ ist - wie sollte da die Singleton-Variante weniger gekoppelt sein können?
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

5

02.01.2015, 21:35

NAja, dann überdenke ich die Sache nochmal. Danke jedenfalls für deine Tipps.

dot

Supermoderator

Beiträge: 9 850

Wohnort: Graz

  • Private Nachricht senden

6

02.01.2015, 21:45

Um was BlueCobold schon gesagt hat vielleicht noch etwas zu veranschaulichen: Wenn deine Ressourcenmanager Singletons sind, kannst du nirgendwo das verwendete Ressourcenmanagerobjekt austauschen, ohne den betroffenen Code selbst zu ändern, da der Code ja explizit einen ganz bestimmten, globalen Ressourcenmanager benutzt. Code, der den Singleton verwendet, ist damit sofort und ausnahmslos an diese eine Instanz eines Ressourcenmanagers gekoppelt. Wenn du den zu verwendenden Ressourcenmanager dagegen überall (z.B. im Konstruktor) durchreichst, kannst du diesen auch überall lokal austauschen. Im Kontrast zur Variante mit Singleton sind alle Ebenen nun auf einmal wunderbar voneinander entkoppelt. Weiterer Vorteil ist, dass alle Abhängigkeiten (wie z.B. "dieses Objekt braucht einen Ressourcenmanager um zu funktionieren") nun explizit in den Schnittstellen, über die Kommuniziert wird, auftauchen und zur Compilezeit forciert werden (du kannst z.B. ein Objekt, das einen Ressourcenmanager braucht nun gar nicht erst erzeugen, ohne zuerst einen Ressourcenmanager zu erzeugen; beim Singleton muss man dagegen immer daran denken, sicherzustellen, dass evtl. notwendige Initialisierungen durchgeführt werden, bevor der Singleton das erste Mal verwendet wird, was unter Umständen zu einem nichttrivialen Problem werden kann).

Singletons führen nicht nur zwangsweise automatisch zu extrem starker Kopplung und garantieren, dass alle ansonsten möglicherweise vorhandene Wiederverwendbarkeit im Keim erstick wird, sondern verstecken diese Kopplung auch noch so gut es nur irgendwie geht (http://en.wikipedia.org/wiki/Action_at_a…_programming%29). Generelle Faustregel: Wann immer man meint, dass man vielleicht einen Singleton verwenden sollte, liegt man falsch.

Abgesehen davon, würde ich generell vielleicht mal drüber nachdenken, wofür so ein "Ressourcenmanager" eigentlich gut sein soll... ;)

Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von »dot« (02.01.2015, 22:05)


7

02.01.2015, 22:04

Mal angenommen, ich gebe dem MaterialManager die zwei Manager ShaderManager und TextureManager mit. Ist das dann akzeptabel, Material via Friend auf Getter für die beiden Manager Zugriff zu geben, oder sollte man wenn schon, dann die Manager auch an alle Materials weitergeben? Wäre letzteres nicht etwas Overhead?

dot

Supermoderator

Beiträge: 9 850

Wohnort: Graz

  • Private Nachricht senden

8

02.01.2015, 22:06

Wieso braucht der MaterialManager einen ShaderManager und einen TextureManager?

9

02.01.2015, 22:08

Beim Laden der Materialien wird der Name von entsprechenden Shadern, oder Texturen in einen Ressourcenreferenz umgewandelt. Diese werden von dem jeweiligen Manager verwaltet.

dot

Supermoderator

Beiträge: 9 850

Wohnort: Graz

  • Private Nachricht senden

10

02.01.2015, 22:11

Ich würde mal meinen, dass das Material dann aber nur die zu verwendenden Ressourcen kennen muss und nicht gleich alle Manager. Die Manager müssen dann also allerhöchstens an der Stelle bekannt sein, wo das Material erzeugt wird... ;)

Werbeanzeige