Шаблон проектирования для нескольких выходных форматов - PullRequest
5 голосов
/ 26 июля 2011

У меня есть структура класса, которая представляет (внутренне) данные, которые я хочу вывести в файл.

Некоторые переменные-члены являются частными для класса данных, так что он может управлять собой и останавливать работунаперекосяк.

Затем я хочу, чтобы эти данные выводились в нескольких форматах файлов.Я мог бы сделать что-то вроде

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

за исключением того, что функции должны затем видеть закрытые переменные-члены DataClass.Конечно, я мог бы просто создать savefile_formatXYZ() функций друзей, но тогда мне нужно было бы добавить объявление друга для каждого другого формата.

Существует ли стандартный шаблон проектирования для решения такого рода задач?Как бы вы решили эту проблему?

Спасибо!

Ответы [ 7 ]

9 голосов
/ 26 июля 2011

В зависимости от сложности вашего класса данных вы можете использовать шаблон посетителя. Если у вас есть какая-то вложенная структура данных, то вам вполне может пригодиться Visitor.

Если форматирование является чем-то относительно простым, например, вы создаете варианты для чего-либо, например, списка через запятую, тогда вы можете использовать такой подход.

Все ваши объекты форматирования реализуют такой интерфейс, как (псевдокод)

 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 голос
/ 26 июля 2011

Если вам нужно реализовать форматирование файла и сохранить / загрузить из вне класса, то вы можете сделать это только с данными, которые общедоступны. Если при сохранении / загрузке необходимо работать с непубличными данными, если при перезагрузке класса невозможно восстановить исходные непубличные данные из общедоступных данных, то в этом должен участвовать либо сам класс, либо друзья этого класса. На самом деле не существует способа обойти это.

Максимум, что вы можете сделать, - это упростить написание новых типов с шаблоном друга. Например:

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.

0 голосов
/ 26 июля 2011

Вы бы сделали это методом для DataClass и передаете поток.

0 голосов
/ 26 июля 2011

Лучшее, что я могу придумать для вашей (проектной) задачи, - это двойное решение:

  • сделать для каждого класса функцию, сериализующую его в XML
  • сделать универсальные функции, которые сохраняют из XML в любой формат, который вы хотите:

    savefile_formatA(XMLNode* pRootNode, ofstream& fout);
    

таким образом, вам нужно сделать только одну функцию сериализации для каждого из ваших классов, и вы также можете сериализовать влюбое количество форматов.

0 голосов
/ 26 июля 2011

Не всегда прибегайте к функции друга, потому что она может легко нарушить инкапсуляцию вашего класса. Будучи другом, он может получить доступ ко всем вашим личным пользователям, независимо от того, надеетесь ли вы на это или нет.

В вашем случае вы можете просто предоставить некоторые общедоступные интерфейсы для возврата необходимых данных клиентам, которые затем будут производить разные форматы. Кроме того, вы можете взглянуть на известный шаблон MVC , если вам интересно.

0 голосов
/ 26 июля 2011

Я думаю, что у вас есть проблема дизайна. Сериализация в файл не должна в любом случае изменять этих данных, так почему эти функции должны быть частными? Если все, что вы делаете, это изучаете данные и записываете их, у вас должен быть соответствующий общедоступный интерфейс.

0 голосов
/ 26 июля 2011

Обычным решением было бы решить, какие данные необходимо экспортировать, и предоставить к ним некоторый доступ (возможно, функции получения).По логике вещей, вы не хотите, чтобы сам класс знал какие-либо подробности о форматах, и вы не хотите, чтобы форматировщики знали о классе больше, чем данные, которые он должен форматировать.

...