これは本当に些細なことのように思えるので、いくつかの要件を見逃していると思います。
メモ化を使用して、結果を複数回計算しないようにします。これはフレームワークで行う必要があります。
フローチャートを使用して、あるモジュールから別のモジュールに情報を渡す方法を決定できます...しかし、最も簡単な方法は、各モジュールが依存するモジュールを直接呼び出すことです。メモ化を使用すると、すでに計算されている場合は問題ないため、それほどコストはかかりません。
どのモジュールについても起動できるようにする必要があるため、それらに ID を付与し、実行時に検索できるようにどこかに登録する必要があります。これには 2 つの方法があります。
- エグザンプラ: この種のモジュールの固有のエグザンプラを取得して実行します。
- Factory: 要求された種類のモジュールを作成し、実行して破棄します。
このメソッドの欠点はExemplar
、モジュールを 2 回実行すると、クリーンな状態から開始するのではなく、最後の (失敗した可能性がある) 実行が残した状態から開始することです。しかし、失敗した場合、結果は計算されません (うーん)。
では、どうすれば... ?
工場から始めましょう。
class Module;
class Result;
class Organizer
{
public:
void AddModule(std::string id, const Module& module);
void RemoveModule(const std::string& id);
const Result* GetResult(const std::string& id) const;
private:
typedef std::map< std::string, std::shared_ptr<const Module> > ModulesType;
typedef std::map< std::string, std::shared_ptr<const Result> > ResultsType;
ModulesType mModules;
mutable ResultsType mResults; // Memoization
};
これは非常に基本的なインターフェイスです。ただし、(再入の問題を回避するために) を呼び出すたびにモジュールの新しいインスタンスがOrganizer
必要になるため、Module
インターフェイスで作業する必要があります。
class Module
{
public:
typedef std::auto_ptr<const Result> ResultPointer;
virtual ~Module() {} // it's a base class
virtual Module* Clone() const = 0; // traditional cloning concept
virtual ResultPointer Execute(const Organizer& organizer) = 0;
}; // class Module
そして今、それは簡単です:
// Organizer implementation
const Result* Organizer::GetResult(const std::string& id)
{
ResultsType::const_iterator res = mResults.find(id);
// Memoized ?
if (res != mResults.end()) return *(it->second);
// Need to compute it
// Look module up
ModulesType::const_iterator mod = mModules.find(id);
if (mod != mModules.end()) return 0;
// Create a throw away clone
std::auto_ptr<Module> module(it->second->Clone());
// Compute
std::shared_ptr<const Result> result(module->Execute(*this).release());
if (!result.get()) return 0;
// Store result as part of the Memoization thingy
mResults[id] = result;
return result.get();
}
簡単なモジュール/結果の例:
struct FooResult: Result { FooResult(int r): mResult(r) {} int mResult; };
struct FooModule: Module
{
virtual FooModule* Clone() const { return new FooModule(*this); }
virtual ResultPointer Execute(const Organizer& organizer)
{
// check that the file has the correct format
if(!organizer.GetResult("CheckModule")) return ResultPointer();
return ResultPointer(new FooResult(42));
}
};
そしてメインから:
#include "project/organizer.h"
#include "project/foo.h"
#include "project/bar.h"
int main(int argc, char* argv[])
{
Organizer org;
org.AddModule("FooModule", FooModule());
org.AddModule("BarModule", BarModule());
for (int i = 1; i < argc; ++i)
{
const Result* result = org.GetResult(argv[i]);
if (result) result->print();
else std::cout << "Error while playing: " << argv[i] << "\n";
}
return 0;
}