多种输出格式的设计模式

时间:2011-07-26 09:31:53

标签: c++ oop design-patterns encapsulation file-format

我有一个类结构,它代表(内部)我希望输出到文件的数据。

某些成员变量对数据类是私有的,因此它可以自行管理并阻止出错。

然后我希望将这些数据输出为多种文件格式。我可以做类似

的事情
savefile_formatA(DataClass* pDataClass, ofstream& fout);
savefile_formatB(DataClass* pDataClass, ofstream& fout);

除了函数需要查看DataClass的私有成员变量。我当然可以只做savefile_formatXYZ()朋友的功能,但我需要为每种不同的格式添加朋友声明。

是否有解决此类问题的标准设计模式?你会如何解决这个问题?

谢谢!

7 个答案:

答案 0 :(得分:9)

根据数据类的复杂程度,您可能希望使用访问者模式。如果您有某种嵌套数据结构,那么访客可能就是您所需要的。

如果格式化是相对简单的,例如,您正在生成诸如逗号分隔列表之类的变体,那么您可以采用这样的方法。

您的格式化程序对象都实现了一个接口,例如(伪代码)

 IFormatter ( start(); addInt(name, value), addString(name, value) .... end() );

然后数据类有一个方法

  public void formatMyself( IFormatter formatter ) {

        formatter.start()
        formatter.addString("aField", myA);
        formatter.addInteger("bfield", myB);
        formatter.end();          
  }

这使得格式化的类负责选择要格式化的数据,格式化程序负责格式的细节。

答案 1 :(得分:1)

如果您需要实现文件格式化并从类的外部保存/加载,那么您只能使用公开可用的数据。如果保存/加载需要处理非公共数据,如果重新加载类不能从公共数据重建原始的非公共数据,则必须涉及类本身或该类的朋友。实际上还没有办法解决这个问题。

您可以做的最多的事情是使用朋友模板更轻松地编写新类型。例如:

class DataType
{
...
private:
    template<typename format> friend void SaveFile<format>(const DataType *, ofstream&);
};

format模板类型为空类型。因此,如果您有formatA和formatB,那么您将拥有空结构:

struct FormatA {};
struct FormatB {};

然后,您需要做的就是为这些格式编写SaveFile的专用版本:

template<> void SaveFile<FormatA>(const DataType *, ofstream&);
template<> void SaveFile<FormatB>(const DataType *, ofstream&);

他们将自动成为DataType的朋友。

答案 2 :(得分:0)

通常的解决方案是决定需要导出哪些数据, 并为它提供某种访问(可能是getter函数)。 从逻辑上讲,您不希望类本身必须知道任何细节 关于格式,你不希望格式化程序知道任何事情 关于课程的更多信息,而不是它必须格式化的数据。

答案 3 :(得分:0)

我认为你在这里遇到的问题是设计问题。无论如何,序列化到文件不应该修改那些数据,那么为什么这些函数应该是私有的呢?如果您所做的只是检查数据并将其写出来,那么您应该拥有足够的公共界面。

答案 4 :(得分:0)

不要总是求助于友元函数,因为它很容易破坏你的类的封装。一旦成为朋友,无论您是否希望看到它,它都可以访问您的所有私人成员。

在您的情况下,您可以简单地提供一些公共接口来将必要的数据返回给客户端,然后生成不同的格式。此外,如果您有兴趣,可以查看着名的MVC pattern

答案 5 :(得分:0)

我能为你的(设计)问题考虑的最好的事情是双重解决方案:

  • 为每个类生成一个将其序列化为XML的函数
  • 制作从xml保存到任何所需格式的通用函数:

    savefile_formatA(XMLNode* pRootNode, ofstream& fout);
    

这样你只需为每个类制作一个序列化函数,你也可以用任意数量的格式进行序列化。

答案 6 :(得分:0)

你可以在DataClass上创建一个方法并传入流。