C++ 如何编写模块间具有良好交互可能性的灵活模块化程序?

C++ 如何编写模块间具有良好交互可能性的灵活模块化程序?,c++,architecture,modular,C++,Architecture,Modular,我在这里查阅了类似主题的答案,但没有找到令人满意的答案。因为我知道这是一个相当大的话题,所以我会尽量说得更具体一些 我想写一个处理文件的程序。处理是非平凡的,因此最好的方法是将不同的阶段分割成独立的模块,然后根据需要使用这些模块(因为有时我只对模块A的输出感兴趣,有时我需要其他五个模块的输出,等等)。问题是,我需要模块协作,因为一个模块的输出可能是另一个模块的输入。我需要它快点。此外,我希望避免多次执行某些处理(如果模块A创建一些数据,然后需要由模块B和C进行处理,我不希望运行模块A两次以创建模

我在这里查阅了类似主题的答案,但没有找到令人满意的答案。因为我知道这是一个相当大的话题,所以我会尽量说得更具体一些

我想写一个处理文件的程序。处理是非平凡的,因此最好的方法是将不同的阶段分割成独立的模块,然后根据需要使用这些模块(因为有时我只对模块A的输出感兴趣,有时我需要其他五个模块的输出,等等)。问题是,我需要模块协作,因为一个模块的输出可能是另一个模块的输入。我需要它快点。此外,我希望避免多次执行某些处理(如果模块A创建一些数据,然后需要由模块B和C进行处理,我不希望运行模块A两次以创建模块B、C的输入)

模块需要共享的信息主要是二进制数据块和/或已处理文件中的偏移量。主程序的任务将非常简单——只需解析参数,运行所需的模块(并可能给出一些输出,或者这应该是模块的任务?)

我不需要在运行时加载模块。将libs与.h文件放在一起,并在每次有新模块或某个模块更新时重新编译程序,这是非常好的。模块的概念主要是因为代码可读性、维护以及能够让更多的人在不同的模块上工作,而不需要一些预定义的接口或任何东西(另一方面,我知道可能需要一些关于如何编写模块的“指南”)。我们可以假设文件处理是只读操作,原始文件没有更改


有人能告诉我如何在C++中做这个好的方向吗?任何建议都是WHEW C++(链接,教程,PDF书籍……)。根据我的经验,在UNIX理念中,使用管道连接在一起的独立程序总是很有用的

如果您的数据不是过大,那么拆分有很多好处。首先,您可以独立测试处理的每个阶段,运行一个程序并将输出重定向到一个文件:您可以轻松地检查结果。然后,即使每个程序都是单线程的,也可以利用多个核心系统,从而更容易创建和调试。您还可以使用程序之间的管道利用操作系统同步。也许您的一些程序也可以使用现有的实用程序来完成


您的最终程序将创建胶水,将您的所有实用程序收集到一个程序中,将数据从一个程序传输到另一个程序(此时不再有文件),并根据您所有计算的需要进行复制。

这看起来非常类似于插件体系结构。我建议从(非正式)数据流程图开始,以确定:

  • 这些块是如何处理数据的
  • 需要传输哪些数据
  • 从一个块返回到另一个块的结果(数据/错误代码/异常)
有了这些信息,您可以开始构建通用接口,它允许在运行时绑定到其他接口。然后,我将向每个模块添加一个工厂函数,以从中请求实际的处理对象。我不建议将处理对象直接从模块接口中取出,而是返回一个工厂对象,在那里可以检索处理对象。然后,这些处理对象用于构建整个处理链

过于简化的大纲如下所示:

struct Processor
{
    void doSomething(Data);
};

struct Module
{
    string name();
    Processor* getProcessor(WhichDoIWant);
    deleteprocessor(Processor*);
};
在我看来,这些模式可能会出现:

  • 工厂功能:从模块中获取对象
  • 复合&装饰:形成加工链

这看起来真的很琐碎,所以我想我们错过了一些要求

用于避免多次计算结果。这应该在框架内完成

您可以使用一些流程图来确定如何使信息从一个模块传递到另一个模块。。。但最简单的方法是让每个模块直接调用它们所依赖的模块。有了记忆,它不会花费太多,因为如果它已经被计算过,你就没事了

因为您需要能够启动任何模块,所以需要给它们ID,并在某个地方注册它们,以便在运行时查找它们。有两种方法可以做到这一点

  • 范例:您获得这种模块的唯一范例并执行它
  • 工厂:您创建一个请求类型的模块,执行它并将其丢弃
examplar
方法的缺点是,如果您执行模块两次,您将不会从干净的状态开始,而是从上次执行(可能失败)留下的状态开始。对于记忆来说,这可能被视为一种优势,但如果失败,则不会计算结果(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 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();
}
从main:

#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;
}
#包括“project/organizer.h”
#包括“项目/foo.h”
#包括“项目/bar.h”
int main(int argc,char*argv[])
{
组织者组织;
org.AddModule(“foodule”,foodule());
org.AddModule(“BarModule”,BarModule());
对于(int i=1;i打印();

Std::这个问题基本上是“我如何编写模块化代码”?因为所有代码都应该是模块化的,这里没有什么特别的C++,或者关于你的特定问题域。答案是“通过应用技巧、天赋和经验”。忘记说我是绑定到Windows操作系统的。我真的只想要一个程序,
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;
}