Design Frage für Asset-Loader Funktionalität



  • Zum Laden meiner Assets verwende ich aktuell ein Template basiertes Interface, von dem die konkreten Loader Abgeleitet werden müssen:

    template<class T>
    class DLL_EXPORT brAssetLoader : public brIAssetLoader
    {                                 
    public:
        brAssetLoader():brIAssetLoader(){}
        virtual ~brAssetLoader(){}
    
        virtual std::shared_ptr<T> load(const std::string& file) const = 0;	
    };
    

    Die Loader werden in einem AssetManager verwaltet, der über eine template basierte Get Methode entweder den angeforderten Objekttypen auf Basis eines bereits geladenen Assets zurückliefert, oder erst dieses Asset über den Loader erstellt und dann das angeforderte Objekt liefert:

    template <class T>
    std::shared_ptr<T> brAssetManager::get(const std::string& file)
    {	
    	std::shared_ptr<T> asset = nullptr;	
    
    	auto iter = m_assets.find(file);
    	if(iter!=m_assets.end()){
    		std::shared_ptr<Asset<T>> value = std::static_pointer_cast<Asset<T>>(iter->second);
    		std::type_index type = typeid(T);
    		if(type!=value->getType()){
    			throw brCore::brIllegalStateException(
    			"[brAssetManager]::load: The Asset target type is not equals to requested type!"
    			);
    		}	
    		asset = value->get();
    	}
    	else{
    		auto loader = this->getLoader<T>();	
    	        asset = loader->load(file);
    
    		std::type_index type = typeid(T);
    		m_assets[file] = std::make_shared<Asset<T>>(type, asset); 			
    	}
    	return asset; 
    }
    

    Soweit so gut. Nun habe ich jedoch den Fall, das ich in einem Loader zwingend mehrere Parameter benötige um das Loading realisieren zu können.

    Eine Möglichkeit währen mehrere Templates für die unterschiedlichen Anforderungen, dass zwingt mich jedoch im Manager, der die Loader verwaltet, zu casten um korrekt zu Laden bzw. für jeden möglichen Fall entsprechend viele Schnittstellen anzubieten, die dann den konkreten Loader verwenden …

    Eine weiter Möglichkeit währe es, das Template um eine Argumenten-Liste basierend auf Variadics zu erweitern:

    template<class T, typename … Args>
    class DLL_EXPORT brAssetLoader : public brIAssetLoader
    {                                 
    public:
        brAssetLoader():brIAssetLoader(){}
        virtual ~brAssetLoader(){}
    
        virtual std::shared_ptr<T> load(const std::string& file, Args&& … args) const = 0;	
    };
    

    Nur dann ist nach Außen nicht mehr zu erkennen, welche Argumente überhaupt übergeben werden können, dass würde lediglich in der Dokumentation der konkreten Applikation sichtbar. Meiner Ansicht nach sehr fehleranfällig.

    Was würdet Ihr bevorzugen? Bzw. sieht jemand von Euch einen weiteren, möglichst eleganten Ansatz um das Problem zu Lösen?

    Währen evtl. Delegates i.V.m. Lambdas ein Ansatz? Wenn ja wie? Der Code zum Laden, ist z.T. recht komplex und benötigt z.T. auch einiges an Subroutinen …



  • Mir ist das ganze System noch nicht wirklich klar. Der Asset Manager scheint hauptsächlich ein Cache zu sein. Dann muss die Schnittstelle aber einheitlich sein, weil der Filename der Key ist. Was ist aber, wenn du weitere Parameter einführst und der erste

    [code="cpp"]
    assetManager.get<AssetType>(fileName, 1);
    [/code]

    aufruft, und der zweite dann

    [code="cpp"]
    assetManager.get<AssetType>(fileName, 2);
    [code="cpp"]

    Dann ist das Objekt nach dem ersten Aufruf bereits im Cache, und die Parameter, die der zweite Aufrufer haben wollte, werden ignoriert.



  • Stimmt, daran hatte ich nicht gedacht. Müsste mir was wegen der Identifizierung überlegen, sollte aber machbar sein z.B. durch Konkanetation der Argumente mit dem Filename: name_1, name_2 usw.

    Bisher habe ich nur den Fall das ich einen Parameter (Name) zusätzlich benötige um aus einer JSON Config eine spezifische Konfiguration zu ermitteln.

    Tendiere daher aktuell zum ersten Ansatz mit 2 verschiedenen Templates.


Anmelden zum Antworten