C++ 正在寻找将可靠原则应用于文件I/O问题的帮助

C++ 正在寻找将可靠原则应用于文件I/O问题的帮助,c++,c++11,solid-principles,C++,C++11,Solid Principles,我正在努力学习更多关于设计模式和原则的知识。我通常在理论上理解它们,但当涉及到将它们应用到现实世界的问题时,我发现自己很难理解它们。这将是一个较长的问题,需要给出所有相关背景,我非常感谢您就如何正确构建这一问题提供任何建议 目前我正在尝试实现一种特定的结构化文件(即TrGeManager)(它是从我在一个不同的软件中导出的)在现代C++中的文件管理器(读写)。此文件可以有三种不同的“风格”(都存储相同的信息,只是使用不同的格式): 短文本文件 长文本文件 二进制文件 所有的口味都有相同的扩展

我正在努力学习更多关于设计模式和原则的知识。我通常在理论上理解它们,但当涉及到将它们应用到现实世界的问题时,我发现自己很难理解它们。这将是一个较长的问题,需要给出所有相关背景,我非常感谢您就如何正确构建这一问题提供任何建议

目前我正在尝试实现一种特定的结构化文件(即TrGeManager)(它是从我在一个不同的软件中导出的)在现代C++中的文件管理器(读写)。此文件可以有三种不同的“风格”(都存储相同的信息,只是使用不同的格式):

  • 短文本文件
  • 长文本文件
  • 二进制文件
所有的口味都有相同的扩展名。用户通常不知道他们处理的是哪一个文件,您必须阅读文件的开头才能分辨出区别

现在我明白了,将表示文件中存储的结构化数据的类TextGrid与I/O分离通常是有意义的。因此,将有一个类
TextGrid
和一个(静态)类
TextGridManager

这就是我迷路的地方。我应该在自己的课堂上实施阅读和写作吗?我是否应该实现一个抽象类BaseTextGridManager,然后派生出专门的类(我认为这是开闭原则的建议)?但是如果是这样的话,用户怎么知道要实例化哪个专用类,因为您必须先读取文件的前几个字节,然后才能知道如何解析它

我当然可以找到一种方法让它以某种方式工作,但我正在寻找如何优雅地做这件事的建议,并遵循坚实的原则。任何见解都将不胜感激

更新: 由于这个问题下面的评论,我目前的计划是以以下方式组织它:

class TextGrid:
{
  // The representation of the TextGrid data
}

class TextGridManager:
{
public:
   static TextGrid readTextGridFile(const std::string& filename);
   static bool writeTextGridFile(const TextGrid& tg, const std::string& filename, const std::string& format);

private:
   TextGridManager(){};
   static TextGrid BinaryTextGridFactory(std::istream& file);
   static TextGrid ShortTextGridFactory(std::istream& file);
   static TextGrid LongTextGridFactory(std::istream& file);
}

我欢迎任何建设性的批评和反馈。

对于新的格式,您将添加新的编写者并让工厂知道。我不是C++的人,但这并不重要。语法为C#,省略了访问修饰符

interface ITextGridReader {
    TextGrid read(filename);
}

class TextGridReader: ITextGridReader {
    // impl read(...);
}

interface ITextGridWriter {
    bool write(filename, textGrid);
}

class BinaryTextGridWriter: ITextGridWriter {
    // imp write(...);
}

class LongTextGridWriter: ITextGridWriter {
    // imp write(...);
}

// Calling code
ITextGridReader reader = new TextGridReader();
TextGrid textGrid = reader.read(...);
ITextGridWriter writer = Factory.CreateTextGridWriter(format);
writer.write(...);

我希望有一个嗅探器函数(可能有足够的部分和状态作为一个类)来确定文件类型,然后有三个不同的工厂函数(也可能有足够的状态作为一个类)来处理每个不同的文件格式。每个工厂函数的输出都是TextGrid.interest。因此,嗅探器功能将与生产TextGrid的三家工厂一起位于TextGridManager中。这个界面的工作原理类似于
TextGrid=TextGridManager::readTextGrid(filename)
,所有的嗅探和不同的解析都对用户隐藏了?但这不会违反开闭原则吗?因为如果(出于任何原因)文件将有第四种格式,那么我无法派生新的管理器,但必须在旧类中添加另一个工厂。就我所理解的原则而言,这正是应该避免的。@Simon解析,事实上,应该隐藏起来。作为API的用户,我不想对实现的细节感到恼火。“这是一个文件/文件名,请给我其中存储的数据。如果在读取/解析过程中发生错误,请通知我(通过(明确定义的)异常或错误代码)”。顶层函数应该看起来像
TextGrid read\u TextGrid(std::string\u view filename)
。与其从原则的角度来思考(由于其泛化性质,在我看来,原则是有争议的),不如考虑抽象的层次。@Sebastian我很欣赏这种观点,但这到底意味着什么呢?