Добрый день, коллеги!
Стала задача спроектировать небольшую систему компьютерного тестирования. Тестирования людей
То есть программу, позволяющую человеку пройти какой-то тест.
Решил поизвращаться с чем-то новым для себя (на данный момент это проектирование вообще и boost), использовать в системе boost::serialization, а частности. Что у меня получилось в требованиях к иерархии классов:
Должен быть главный класс (предположительно синглетон) DataBase, который определяет методы для чтения данных с диска/сохранения изменений на диск. Предположительно, в начале работы данные о тестах и статистике читаются скопом, в конце статистика изменяется, и сбрасывается обратно на диск.
Класс DataBase позволяет вытащтиь с себя список тестов (Test), тот, в свою очередь, список вопросов (Question), а они — список ответов (Answer).
Предположительно, DataBase содержит вектор Test'ов, каждый Test — вектор Question'ов, каждый Question — вектор Answer'ов. Вытаскиваться должны _итераторы_ (причем неплохо чтобы стандартные, не рукописные) — мало ли чего мне захочется с ними делать
Как это примерно хотелось бы видеть в коде:
vector<Test>* tests_array = DataBase::GetTests();
for (int i = 0; i < tests_array[0]->GetQuestions()->count; i++){
...
}
Перейду, собственно, к самому вопросу. DataBase сохраняет/извлекает данные через boost::serialization. Чтобы не загромождать этот "главный" класс тонкостями работы с сохранинием/извлечением данных, я выношу все, что с этим связано, в DataBaseImpl — использую "мост". Теперь в конструкторе DataBase'а мне надо только проинициализировать пимпл, а он загрузит данные. Соответственно, то же нужно сделать и со всеми другими классами: Test, Question, Answer.
Теперь — что получается. DataBaseImpl на самом деле содержит не vector<Test>, а vector<TestImpl> (т. к. Test не позволяет себя сериализовать), возвращать же он должен vector<Test>. Набросал тестовые классы, получил что-то такое:
class TestImpl{
};
class Test{
public:
Test (TestImpl) {}
};
class DBImpl{
private:
std::vector<TestImpl> tests_;
public:
std::vector<Test> GetTests(){
std::vector<Test> ret;
ret.assign(tests_.begin(), tests_.end());
return ret;
}
};
class DB{
private:
DBImpl* pimpl_;
public:
Test Get() {return pimpl_->GetTests()[0];}
};
Вот. Не очень-то красиво, как мне кажется. Да и плюс если делать статистику в том же ключе, то поднимается вопрос об изменении векторов — хорошо, отдал я новую копию вектора, а для изменений придется еще Commit() какой-нибудь дописывать?..
Что предложите, многоуважаемые гуру? Думается мне, что в дизайне вообще где-то бооольшой косяк забит.