Дописал вчера комменты в проекте. Уффф....
А потом вернулся я к рабочим вопросам и, помедитировав, понял, что появилась у нас небольшая загвоздка с загрузкой... но сначала - пару слов об общем.
Суровые программистские будни, многобуковИтак, есть некоторая база данных (БД) с некоторым набором таблиц. Часть из таблиц представляют собой некоторый справочный материал, который нужен клиентской программе (клиенту) для работы. Таблиц таких много и данные в них различны по структуре, так что возникает задача предоставления этих данных клиенту. Эту задачу можно решать на стороне сервера, формируя нужный результат и передавая его клиенту, но такой подход крайне нежелателен, поскольку он имеет проблемы с расширяемостью, да и для нескольких клиентов сильно проигрывает в скорости. Гораздо практичнее передать все данные из таблиц клиенту и пусть он делает с ними все, что захочет, а сервер в это время сможет обрабатывать другие запросы.
Однако и тут не все гладко. Данные различны по структуре и имеют четкую классификацию, а значит, их нельзя смешивать. После некоторых мытарств было решено написать класс справочника, который будет представлять любую справочную информацию клиенту, которая требуется.
Сказано - сделано.
Не буду описывать то, что было в процессе, а только результат. У нас получилась иерархия классов, основные из которых являются шаблонами, т.е. разворачиваются в процессе компиляции. У нас есть класс справочника, который предоставляет клиенту некоторые методы доступа, скрывая внутреннее устройство, класс узла справочника для представления иерархической структуры и скрытый от клиента (класс объявлен как закрытый внутри класса справочника), а также класс элемента справочника, представляющий хранимое значение. Справочник и его элемент параметризуются некоторой структурой, представляющей доступные поля элемента справочника.
При загрузке справочник получает записи из таблицы (свои элементы), создает для них узлы и записывает их в ассоциативный контейнер, индексируя их, т.о. по их уникальным номерам (ИДам). Затем вызывается глупая процедура, которая пробегает по всему контейнеру и проставляет иерархические связи между узлами в соответствии с указанным ИДом родительского узла. ИДы, естесственно, сокрыты в элементе и доступны только на чтение.
Казалось бы, что все прекрасно и удобно. Для простых справочников с одним деревом элементов - да. Но у нас ведь есть не только простые справочники, но и всякие пакости вроде справочников с некоторым уровнем вложенности (чтоб их)! И тут возникает вопрос - как с помощью имеющейся структуры представить такие "нехорошие справочники", у которых элементы кроме своих полей имеют еще и вложенный, внутренний справочник? Про структуру и речи не шло - и очевидно, что делать надо именно с вложенностью, а не 2 и более отдельных справочника. А вот с загрузкой возникают проблемы.
Рассмотрим проблему на примере двухуровневой иерархии. Самый простой вариант загрузки - это выполнить запрос на загрузку родительского элемента, а затем, в процедуре получения хранимых в нем полей, вызвать процедуру загрузки внутреннего справочника. Решение простое, для реализации его в текущей иерархии - написать 3-4 строки кода. к тому же оно не нарушает инкапсуляции. Минус у него - огромная тормознутость из-за большого количества выполняемых запросов.
Второй вариант - нарушить инкапсуляцию, сделав загрузку в клиенте "извне" справочника. Быстрое, но ненадежное решение.
Еще можно "пригрузить" сервер, чтобы он формировал у себя некоторую виртуальную таблицу со всеми нужными данными. Решение плохое, т.к. нагрузки на сервер хочется избежать, да и клиент выполнит быстрее.
В конце раздумий пришли к следующему: отделить загрузку от справочника и для этой цели написать класс, который будет дублировать интерфейс класса для работы с БД и формировать нужную виртуальную таблицу в памяти клиента, после чего предоставлять к ней доступ через тот же интерфейс. Плюс этого решения в скорости, в малой загруженности сервера и в инвариантности относительно требуемого справочника - можно использовать один и тот же загрузчик для работы с разными справочниками в пределах одного уровня иерархии. Сам же загрузчик допускает варьируемость посредством отделения правила формирования виртуальной таблицы.
На этом пока и остановились... пока что готовлю диаграмму классов и думаю над интерфейсами.Вот такая вот у нас жизня. Остро ощущаю нехватку опыта в проектировании - очень жалею, что меня этому не учили в университете. Составил себе список книг, которые
обязательно надо прочитать:
1) Саттер Г., Александреску. А. Стандарты программирования на языке Си++.
Отличный сборник рекомендаций, всем советую.2) Вандевуд Д., Джоссатис Н.М. Шаблоны С++: Справочник разработчика.
Это единственный правильный учебник по шаблонам, который я когда-либо видел. Содержит очень много интересного и прекрасно помогает при разработке обобщенных классов или функций.3) Фаулер М. Рефакторинг. Улучшение существующего кода.
4) Влиссидес Дж. Применение шаблонов проектирования.
Книга рассчитана на читателя, знакомого с шаблонами проектирования авторства "Банды четырех" (Гамма, Хелм, Джонсон, Влиссидес). Читать однозначно стоит.5) Александреску А. Современное проектирование на С++.
Сам так и не листал, но знакомые с книгой говорят, что труд очень сложный. Так что возьмусь за него нескоро.6) Элджер Дж. Библиотека программиста на Си++.
Нуу... у меня немного хромает знание стандартов языка =^.^=7) Страуструп Б. (не помню название)
По той же причине, что и п. 6 А вот книгу Гамма, Хелм, Джонсон, Влиссидес. "Приемы объектно-ориентированного программирования. Паттерны проектирования." оч хочется видеть у себя на полке. Ибо оч полезно как справочный материал.