Design pattern for multiple output formats

2019-02-17 12:25发布

I have a class structure which represents (internally) the data I wish to output to a file.

Some of the member variables are private to the data class so that it can manage itself and stop things going awry.

I then want this data to be output into a number of file formats. I could do something like

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

except that the functions need to then see the private member variables of DataClass. I could of course just make savefile_formatXYZ() friend functions but then I would need to add a friend declaration for every different format.

Is there a standard design pattern for solving this kind of thing? How would you solve this problem?

Thanks!

7条回答
可以哭但决不认输i
2楼-- · 2019-02-17 13:06

If you need to implement file formatting and save/load from outside of the class, then you can only do it with data that is publicly available. If saving/loading needs to deal with non-public data, if reloading the class cannot reconstruct the original non-public data from public data, then either the class itself or friends of that class must be involved. There's not really a way around that.

The most you might be able to do is to make it easier to write new types, with a friend template. For example:

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

The format template type would be empty types. So if you have formatA and formatB, you would have empty structs:

struct FormatA {};
struct FormatB {};

Then, all you need to do is write specialized versions of SaveFile for those formats:

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

They will automatically be friends of DataType.

查看更多
倾城 Initia
3楼-- · 2019-02-17 13:06

Don't always resort to friend function because it can easily break the encapsulation of your class. Once friend, it can access all your private members no matter whether you hope it see or not.

In your case, you can simply provide some public interfaces to return the necessary data to clients which will produce different formats then. Furthermore, you can take a look at famous MVC pattern if you're interested.

查看更多
干净又极端
4楼-- · 2019-02-17 13:11

The usual solution would be to decide what data needs to be exported, and to provide some sort of access (probably getter functions) to it. Logically, you don't want the class itself to have to know any details about the formats, and you don't want the formatters to know anything more about the class than the data it has to format.

查看更多
狗以群分
5楼-- · 2019-02-17 13:22

Depending upon the complexity of your data class you may wish to use a Visitor pattern. If you have some kind of nested data structure then Visitor may well be what you need.

If formatting is something relatively simple, for example you are producing variations on something such as a comma separated list then you can take an approach like this.

Your formatter objects all implement an interface such as (pseudo code)

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

then the data class has a method

  public void formatMyself( IFormatter formatter ) {

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

This makes the class being formatted responsible for the choice of data to be formatted, and the formatter responsible for the details of the format.

查看更多
Root(大扎)
6楼-- · 2019-02-17 13:22

The best thing I can think of for your (design) problem is a two fold solution:

  • make for each class a function that serializes it to XML
  • make generic functions that save from xml to any format you want:

    savefile_formatA(XMLNode* pRootNode, ofstream& fout);
    

this way you need to make only one serializing function for each of your classes and you can also serialize in any number of formats.

查看更多
萌系小妹纸
7楼-- · 2019-02-17 13:23

You would make it a method on DataClass and pass in the stream.

查看更多
登录 后发表回答