Алексей Игнатенко
Независимый программный модуль, обычно подключаемый на этапе выполнения программы
Улучшение качества и однородности кода Четкая инкапсуляция деталей реализации за интерфейсами Инкапсуляция сторонних библиотек Улучшение модульности проекта В каждый момент времени идет работа с небольшим подмножеством файлов Лучший способ организации больших проектов Радикальное уменьшение времени сборки Не производится обработка внутренних заголовочных файлов для других компонент Не требуется пересборка других компонент Возможность замены компонентов Возможность обновления не всей программы, а только набора компонент Возможность выбора из нескольких однотипных компонент (конфигурация) Возможность использования компонент с различными открытыми/закрытыми лицензиями Таким образом можно использовать GPL-компоненты и раскрывать их код, не нарушая лицензии
Общий проект разделяется на набор компонентКомпоненты помещаются в отдельные DLL В процессе выделения создаются интерфейсы, которые используется в основном проекте (SDK) DLL с компонентам подгружаются на этапе выполнения
Обычные DLL связываются на этапе компиляции Компоненты подгружаются во время выполнения в два этапа: Поиск всех компонент (в определенном каталоге) Регистрация найденных компонент в определенном месте системы
DLL: IPlugin *createInstance(const char *); Application: IPlugin* pluginInstance = createInstance(RendererPlugin); IRenderer* renderer = dynamic_cast (pluginInstance)
Одно из трех: Нарушается безопасность типов static_cast Ограничивается применение плагинов dynamic_cast Необходима разработка сложной и ломкой кастомной RTTI QueryInterface Необходимы дополнительные соглашения для поиска однотипных плагинов (по имени, например)
Интерфейсы определяется в приложении Для интерфейсов применяются соглашения COM Плагины региструются сами в нужном месте системы
Application: DLL:
Система разрабатывается с нуля для поддержки плагинов
А нужно ли поддерживать возможность работы из разных сред? Версии интерфейсов / библиотек Суперклассы - да/нет Приведение типов Подсчет ссылок Как искать плагины? События
Если нет требований, чтобы плагины и/или основное приложение работали из разных сред, нет смысла поддерживать соглашения COM Не нужны STDMETHODCALLTYPE, BSTR и т.п. Можно выделять и удалять память в разных DLL (это стоит проверить) Более того: можно использовать набор базовых неабстрактных классов и подключать общую библиотеку ко всем плагинам Внимание: но нужно очень четко работать с версиями в этом случае!
Проверять версии 1) У библиотеки (DLL) 2) У плагина (интерфейса) Как проверять? Как поддерживать совместимость? Старые плагины должны работать с новыми интерфейсами? Новые плагины должны работать со старыми интерфейсами?
Функции: запрос на информацию без создания экземпляра = статические функции Создание объекта = фабрика Нужны ли? Накладные расохды на создание/поддержку
Dynamic_cast QueryInterface
AddRef/Release – единственный вариант. Есть ли другие возможности? Если нет, почему?
Перебор файлов в папках Конфиг-файл (XML – рекомендуется MS) В реестре (пишется инсталлятором)