Я работаю над структурой плагинов, использующей динамически загружаемые разделяемые библиотеки, которая основана на модели точек расширения Eclipse (и, возможно, других). Все плагины имеют схожие свойства (имя, идентификатор, версия и т. Д.), И каждый плагин теоретически может удовлетворить любую точку расширения. Фактическая обработка плагина (т.е. Dll) управляется другой библиотекой, и все, что я делаю, на самом деле - это управление наборами интерфейсов для приложения.
Я начал с использования enum PluginType
для различения различных интерфейсов, но я быстро понял, что использование шаблонных функций сделало код намного чище и оставило бы основную работу на компиляторе, а не заставляло меня использовать много switch {...}
заявления.
Единственная проблема заключается в том, что мне нужно указать одинаковую функциональность для членов класса - наиболее очевидный пример - плагин по умолчанию, который предоставляет определенный интерфейс. Класс Settings
обрабатывает все настройки, включая плагин по умолчанию для интерфейса.
т.е. Skin newSkin = settings.GetDefault<ISkin>();
Как сохранить значение по умолчанию ISkin
в контейнере, не прибегая к каким-либо другим средствам идентификации интерфейса?
Как я упоминал выше, в настоящее время я использую std::map<PluginType, IPlugin> Settings::defaults
член для достижения этой цели (где IPlugin
является абстрактным базовым классом, от которого происходят все плагины. Затем я могу dynamic_cast
перейти к нужному интерфейсу, когда это необходимо, но это мне кажется, пахнет плохим дизайном и приносит больше вреда, чем пользы, я думаю.
будет приветствовать любые советы
edit: вот пример текущего использования плагинов по умолчанию
typedef boost::shared_ptr<ISkin> Skin;
typedef boost::shared_ptr<IPlugin> Plugin;
enum PluginType
{
skin,
...,
...
}
class Settings
{
public:
void SetDefault(const PluginType type, boost::shared_ptr<IPlugin> plugin) {
m_default[type] = plugin;
}
boost::shared_ptr<IPlugin> GetDefault(const PluginType type) {
return m_default[type];
}
private:
std::map<PluginType, boost::shared_ptr<IPlugin> m_default;
};
SkinManager::Initialize()
{
Plugin thedefault = g_settings.GetDefault(skinplugin);
Skin defaultskin = boost::dynamic_pointer_cast<ISkin>(theskin);
defaultskin->Initialize();
}
Я бы скорее назвал getdefault следующим образом с автоматическим приведением к производному классу. Однако мне нужно специализироваться для каждого типа класса.
template<>
Skin Settings::GetDefault<ISkin>()
{
return boost::dynamic_pointer_cast<ISkin>(m_default(skin));
}