2

我有几个从基类推迟的类File_plugin。我想在 class 的每个实例中都有每个类的实例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)。它现在没有实施,但将来会实施。我认为我当前的实现允许这样做,但我没有检查。

这种实现的最大问题是插件搜索速度慢(使用forand dynamic_cast)。所以我不能只是get_plugin到处调用,我必须存储返回值并将其用于快速访问。不舒服。此外,这个解决方案看起来并不完美。有没有办法让它变得更好?

4

1 回答 1

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>();
}
于 2012-05-27T16:22:02.527 回答