Esistono alcuni modi per controllare quale tipo di risorse restituire. Dipenderà da come un utente della tua libreria utilizza la libreria. Se includono l'origine completa (come fanno Unity e Unreal Engine), il modo più semplice è richiedere a un utente della tua libreria di definire quale sistema stanno usando - OpenGL o DirectX - in fase di compilazione. Potrebbe essere necessario che l'utente definisca alcune macro del preprocessore come questa:
#define IMPLEMENTATION_OPENGL 1
per OpenGL e
#define IMPLEMENTATION_DIRECTX 1
per DirectX.
È necessario che un utente della tua libreria definisca quale di questi utilizzare in alcune intestazioni precompilate. Quando il compilatore ha ottenuto i file della tua libreria, controllerebbe quale compilare, in questo modo:
class ITextureLoader {
public:
ITextureLoader(const char* imagePath);
~ITextureLoader();
// ... etc.
};
#if IMPLEMENTATION_OPENGL
class TextureLoaderOpenGL : public ITextureLoader {
public:
TetxureLoaderOpenGL(const char* imagePath);
~TextureLoaderOpenGL();
//... etc.
};
#elif IMPLEMENTATION_DIRECTX
class TextureLoaderDirectX : public ITextureLoader {
public:
TetxureLoaderDirectX(const char* imagePath);
~TextureLoaderDirectX();
//... etc.
};
#endif
Quindi avresti un TextureLoaderFactory
che restituirebbe un oggetto ITextureLoader
come questo:
ITextureLoader* CreateTextureLoader(const char* imagePath)
{
#if IMPLEMENTATION_OPENGL
return new TextureLoaderOpenGL(imagePath);
#elif IMPLEMENTATION_DIRECTX
return new TextureLoaderDirectX(imagePath);
#endif
}
Se non si include la fonte per gli utenti, è necessario decidere in fase di esecuzione. In questo caso potrebbe essere più semplice creare solo 2 librerie diverse per l'utente. Non è molto frequente che un utente voglia utilizzare sia OpenGL che DirectX nella propria applicazione.
Potresti anche averli creare una sorta di oggetto di contesto che definisce cose come il renderer da usare. Passano quindi quell'oggetto contestuale ai metodi factory che creano gli oggetti concreti. Qualcosa del genere:
enum Technology {
Technology_OpenGL = 1,
Technology_DirectX = 2
} Technology;
struct TechnologyContext {
Technology tech;
int majorVersion;
int minorVersion;
};
Quindi la tua fabbrica sarebbe simile a questa:
ITextureLoader* CreateTextureLoader(const TechnologyContext& ctx, const char* path)
{
if (ctx.tech == Technology_OpenGL)
{
return new TextureLoaderOpenGL(path);
}
else
{
return new TextureLoaderDirectX(path);
}
}
Come utente, lo troverei più ingombrante, personalmente.