Я пишу слой абстракции поверх некоторого графического API (DirectX9 и DirectX11), и мне хотелось бы узнать ваше мнение.
Традиционно я бы создавал базовый класс для каждой концепции, которую я хочу абстрагировать.
Таким образом, в типичной ОО-моде у меня есть, например, класс Shader и 2 подкласса DX9Shader и DX11Shader.
Я бы повторил процесс для текстур и т. Д. ... и когда мне нужно создать их экземпляр, у меня есть абстрактная фабрика, которая будет возвращать соответствующий подкласс в зависимости от текущего графического API.
После RAII возвращенный указатель будет инкапсулирован в std :: shared_ptr.
Пока все хорошо, но в моем случае есть несколько проблем с этим подходом:
- Мне нужно придумать открытый интерфейс, который инкапсулирует функциональность обоих API (и других API в будущем).
- Производный класс хранится в отдельных библиотеках DLL (одна для DX9, одна для DX11 и т. Д.), И наличие для них shared_ptr в клиенте является проклятием: при выходе графические библиотеки выгружаются, а если клиент все еще имеет shared_ptr для одного из графических объектов boom , сбой из-за вызова кода из незагруженной DLL.
Это побудило меня переделать способ, которым я делаю вещи:
Я думал, что смогу просто вернуть необработанные указатели на ресурсы и иметь графический интерфейс API чистым после себя, но все еще остается проблема висячих указателей на стороне клиента и проблемы интерфейса.
Я даже считал ручной подсчет ссылок похожим на COM, но подумал, что это будет шагом назад (поправьте меня, если я ошибаюсь, если исходить из мира shared_ptr, ручной подсчет ссылок кажется примитивным).
Затем я увидел работу Хумуса, где все его графические классы представлены целочисленными идентификаторами (очень похоже на то, что делает OpenGL).
Создание нового объекта возвращает только его целочисленный идентификатор и сохраняет указатель внутри; это все совершенно непрозрачно!
Классы, представляющие абстракцию (например, DX9Shader и т. Д.), Все скрыты за API устройства, который является единственным интерфейсом.
Если кто-то хочет установить текстуру, это просто вопрос вызова устройства-> SetTexture (ID), а все остальное происходит за кулисами.
Недостатком является то, что скрытая часть API является раздутой, для работы системы требуется много кода, и я не являюсь поклонником класса "сделай все".
Есть идеи / мысли?