Design-Frage Zuordnung zw. Klassen



  • Hi,
    Ich hätte da ein Design Problem und hoffe hier Hilfe zu finden.
    Da der eigentliche Code zu umfangreich ist, poste ich es in verringerter Form.
    Es existiert eine Klasse A mit Rohdaten(u.A. ein String), dazu eine Klasse Manager_A, welche eine Liste von A-Objekten verwaltet:

    class A{
    	std::string Name;
    	// Data
    };
    class Manager_A{
    	std::vector<A> As;
            ...
    };
    

    Dann habe ich noch eine Klasse B und eine Manager_B Klasse die wiederum eine "Liste" von B-Objekten verwaltet.

    class B{ // abstrakt
    	// Data
    };
    class Manager_B{
    	"Liste"<B> Bs;
    	public:
    		void tick();
            ...
    };
    

    Nun gibt es eine Beziehung zwischen B bzw jedem Untertyp von B und A -> Jedes B "benötigt/verwendet" ein A.
    Welches A das ist, ist abhängig von dem string Name in A und dem Untertyp von B um den es sich handelt.
    Wobei ein A Objekt recht groß ist und nur einmal im Speicher steht. Also ein Untertyp von B hat genau ein A, wobei ein A von mehreren Objekten eines Untertyps von B verwendet werden kann.

    Manager_B iteriert nun in tick() durch all seine Member und ruft für jedes Manager_A auf. Welcher wiederum das zu dem aktuellen B zugehörige A liefert.
    Die Art der Abfrage welches A zu welchem B gehört ist Teil des Problems(siehe weiter unten)

    <pseudocode>
    void Manager_B::tick(){
    	for(Bs -> actual_B)
    	    Manager_A::GetInstance.(actual_B).DoSmth();
    }
    </pseudocode>
    

    Nun zu dem eigentlichen Problem:
    In Manager_B gibt es wie angemerkt eine "Liste" mit B-Objekten. Bei den Vorgängen in tick() ist es allerdings wichtig, dass alle B-Objekte mit "gleichem" A in Folge aufgerufen werden. Diese Liste sollte also geordnet sein.

    Erst dachte ich daran jedem B einen Pointer auf ein A-Objekt in Manager_A zu geben, allerdings gebe ich einer außenstehenden Klasse ungern Zeiger/Referenzen auf Objekte, die von einer anderen verwaltet werden. Darüberhinaus löst das nicht das Problem, dass die Objekte geordnet sein müssen.

    Nach einigen Überlegungen habe ich folgende "Lösung" gefunden:

    Die "Liste" ist eine std::map< unsigned int, std::vector<B> > Bs;
    Wobei alle Bs mit gleichem A in dem vector<B> gespeichert werden und der unsigned int für den Index des dazugehörigen A in Manager_A steht.

    Der Vorteil ist, dass alle Bs mit gleichem A nacheinander behandelt werden können, es keinerlei Sortierung zur Laufzeit benötigt und nicht jedes B einen Key auf ein A speichern muss.
    Die Einfügemethode von Manager_B bekommt einen string übergeben, prüft welchem A dieser in Manager_A entspricht und speichert sich den Index als unsigned int.
    Bei den Vorgängen in tick() benötigt man keine Suche in der Map oder den vector<B>, denn da ohnehin alle behandelt werden müssen, kann man einfach durchiterieren.

    Meine Frage ist nun, ob es da nicht eine bessere Lösung geben könnte, da mir das Design nicht so gut erscheint.
    Besonders da jedes Mal wenn ein B hinzugefügt wird, alle A durchlaufen werden müssen
    und "Name" mit dem übergebenen String verglichen werden muss.

    Eine Alternative die mir einfällt, wäre eine Liste die alle B speichert. Diese müsste dann aber auch sortiert werden/bleiben.
    Darüberhinaus dachte ich noch an eine Lösung direkt über Polymorphie, wobei es dann für jeden Subtyp von B eine static variable bräuchte die den Index des zugehörigen As bzw.
    einen Pointer darauf speichert + eine geordnete Liste benötigt, da die Ordnungsstruktur eine Ebene tiefer (an die Objekte) weitergegeben wird.

    Ich würde mich über Vorschläge freuen.
    MfG



  • Niemand eine Idee?



  • Klingt irgendwie merkwürdig. Erklär uns vielleicht mal, was die konkrete Anwendung ist, bzw. welches konkrete Problem du lösen willst.



  • Wenn Du für Deine Map statt des Index für A einen Hashcode von A verwendest (den A bereit stellt) musst Du beim Einfügen nicht erst das passende A suchen.

    In Deinem Fall könntest Du zum Beispiel string A::getname() verwenden, sofern der für jedes mögliche Objekt von A eindeutig ist.

    Grundsätzlich solltest Du Dir aber überlegen, dass wenn B::anyB und A::anotherA eine Beziehung haben, es vielleicht sinnvoll ist, die direkt in den Klassen abzubilden. Das spart zumindest einige Indirektionen über die "Manager"-Klassen.

    Etwa so:

    void Manager_B::addObject(const B& b)
    {
        bs[b.getAssociatedAName()].push_back(b);
    }
    

Anmelden zum Antworten