我有几个从基类File_plugin
推迟的类。我希望在类File
的每个实例中都有一个每个类的实例。
这是一个天真的实现:
class File {
public:
File(): plugin1(this), plugin2(this), /*... */ {}
Plugin1 plugin1;
Plugin2 plugin2;
Plugin3 plugin3;
Plugin4 plugin4;
};
class File_plugin {
public:
File_plugin(File* p_file): file(p_file) {}
protected:
File* file;
};
class Plugin1: public File_plugin {
void some_action() {
//we can access another plugin as:
Plugin2* p2 = &( file->plugin2 );
}
};
但是File
类必须知道所有插件的实现,这很糟糕。我们通常在每个地方尽可能使用前向声明。
因此,File
一定不能知道插件的实现,甚至不知道类名列表。一些插件将在运行时从DLL加载,因此我们在编译时不知道它们的名称。
此外,插件必须不知道几乎所有其他插件的存在。但是如果一个插件知道其他插件,它必须能够获得这个插件的对象并使用它。
现在我正在使用以下实现:
class File {
public:
File() : plugins(Plugins_registry::get_file_plugins(this)) { }
template<class T>
T *get_plugin() {
foreach(File_plugin *p, plugins) {
T* o = dynamic_cast<T*>(p);
if (o) return o;
}
throw Bad_exception(tr("File plugin not found"));
}
private:
QList<File_plugin*> plugins;
}
QList<File_plugin*> Plugins_registry::get_file_plugins(File* file) {
QList<File_plugin*> list;
list << new Plugin1(file);
list << new Plugin2(file);
list << new Plugin3(file);
list << new Plugin4(file);
//code below is untested
QPluginLoader loader("plugin5.dll");
list << dynamic_cast<My_plugin_class>(loader.instance)->get_file_plugin();
return list;
}
class Plugin1: public File_plugin {
void some_action() {
//we can access another plugin as:
Plugin2* p2 = file->get_plugin<Plugin2>();
}
};
某些插件可以存储在外部库中(在Windows上表示为DLL)。它现在没有实现,但将来会实现。我认为我目前的实施允许,但我没有检查。
此实现的最大问题是插件搜索速度慢(使用for
和dynamic_cast
)。
所以我不能只在任何地方调用get_plugin
,我必须存储返回的值并将其用于快速访问。这很不舒服。
此外,这个解决方案看起来并不完美。有没有办法让它变得更好?
答案 0 :(得分:1)
以下是如何通过为每个插件类型创建地图来实现它的示例:
class File {
public:
File() { }
template<class T>
T *get_plugin() {
T *result = T::getInstance(this);
if (!result) {
throw Bad_exception(tr("File plugin not found"));
}
return result;
}
};
class File_plugin {
public:
File_plugin(File *file)
: file(file)
{
}
protected:
File *file;
};
template <class Plugin>
class Basic_File_Plugin : public File_plugin {
public:
Basic_File_Plugin(File *file,Plugin *plugin)
: File_plugin(file)
{
instances[file] = plugin;
}
~Basic_File_Plugin()
{
instances.erase(file);
}
static Plugin *getInstance(File *file)
{
return instances[file];
}
private:
static std::map<File *,Plugin *> instances;
};
template <class Plugin>
std::map<File *,Plugin *> Basic_File_Plugin<Plugin>::instances =
std::map<File *,Plugin *>();
class Plugin1 : public Basic_File_Plugin<Plugin1> {
public:
Plugin1(File *file)
: Basic_File_Plugin<Plugin1>(file,this)
{
}
void some_action();
};
class Plugin2 : public Basic_File_Plugin<Plugin2> {
public:
Plugin2(File *file)
: Basic_File_Plugin<Plugin2>(file,this)
{
}
};
void Plugin1::some_action()
{
Plugin2 *p2 = file->get_plugin<Plugin2>();
}