这看起来真的很微不足道,所以我想我们错过了一些要求。
使用Memoization避免多次计算结果。这应该在框架中完成。
您可以使用一些流程图来确定如何使信息从一个模块传递到另一个模块......但最简单的方法是让每个模块直接调用它们所依赖的模块。使用记忆化它不会花费太多,因为如果它已经被计算过,你就可以了。
由于您需要能够启动任何模块,因此您需要为它们提供 ID 并在某处注册它们,以便在运行时查找它们。有两种方法可以做到这一点。
- Exemplar:获取此类模块的唯一示例并执行。
- 工厂:您创建一个请求类型的模块,执行它并将其丢弃。
该Exemplar
方法的缺点是,如果您执行模块两次,您将不会从干净状态开始,而是从最后一次(可能失败)执行留下的状态开始。对于记忆,它可能被视为一个优势,但如果它失败了,则不会计算结果(urgh),所以我建议不要这样做。
那你怎么……?
让我们从工厂开始。
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;
}