2

基本クラスから延期されたいくつかのクラスがあり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。戻り値を保存して、高速アクセスに使用する必要があります。不快です。また、このソリューションは完璧に見えません。それを改善する方法はありますか?

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 に答える