в течение некоторого времени я работал над приложением. Поскольку программирование - это просто хобби, этот проект уже слишком длинный, но, кроме того. Я сейчас нахожусь в точке, где каждая "проблема" становится чрезвычайно трудной для решения. И я думаю о рефакторинге кода, однако это приведет к "полной" перезаписи.
Позвольте мне объяснить проблему и как я ее решил в настоящее время. В основном у меня есть данные, и я позволяю вещам происходить по этим данным (хорошо, я описал каждую программу, не так ли?). Что происходит:
Данные → запрашивает просмотрщик → просмотрщик отображает данные на основе фактических данных viewer возвращает пользовательский ввод → data → запрашивает "исполнитель" для его выполнения → новые данные
Теперь это работало очень хорошо, и я думал, что изначально "эй, я мог бы, например, сменить командную строку на qt или windows - или даже взять этот внешний (С#) и просто вызвать эту программу".
Однако по мере роста программы она становилась все более утомительной. Самое главное, что данные отображаются по-разному, в зависимости от того, что данные и что еще важнее, где они расположены. Поэтому я вернулся к дереву и добавил, чтобы "отслеживать" то, что у родительской линии ". Тогда общий просмотрщик будет искать наиболее конкретный фактический виджет. Он использует список с [location; виджета] и находит наилучшее совпадающее местоположение.
Проблемы возникают при обновлении для новых "данных" - мне нужно пройти через все активы - зритель, заставка и т.д. Обновление механизма проверки дало мне много ошибок. Такие вещи, как "эй, почему он отображается неправильный виджет теперь снова?".
Теперь я могу полностью поменять это. И вместо дерева datastructure вызова общего зрителя. Я использовал бы внутренние возможности дерева OO. Узлы были бы childs (&, когда требуется новый просмотрщик или механизм сохранения, формируется новый ребенок).
Это позволит удалить сложный механизм проверки, где я проверяю местоположение в дереве. Однако это может открыть целую другую червь червей. И мне хотелось бы получить некоторые комментарии по этому поводу? Должен ли я держать зрителя совершенно отдельным - с трудностью проверки данных? Или новый подход лучше, но он объединяет данные и выполнение в один node. (Так что, если я хочу перейти с qt на cli/С#, это становится практически невозможным)
Какой метод следует использовать в конце? Также есть что-то еще, что я могу сделать? Чтобы зритель не раздельный, все же не нужно делать проверки, чтобы увидеть, какой виджет должен отображаться?
EDIT, просто чтобы показать некоторый "код" и как работает моя программа. Не уверен, что это хорошо, как я уже сказал, это стало довольно сложной методологией.
Предполагается объединить несколько проектов "gamemaker" вместе (как GM: студии странно не хватает этой функции). Файлы проектов Gamemaker - это просто наборы xml файлов. (Основной файл xml с единственными ссылками на другие файлы xml и файл xml для каждого ресурса -объекта, спрайт, звук, комнату и т.д.). Однако есть некоторые "причуды", из-за которых невозможно прочитать что-то вроде деревьев свойств boost или qt: 1) порядок атрибутов/дочерних узлов очень важен в определенных частях файлов. и 2) пустое пространство часто игнорируется, однако в других точках очень важно его сохранить.
Считается, что есть также много точек, где node точно такой же. Как то, как фон может иметь <width>200</width>
, и комната тоже может это иметь. Тем не менее для пользователя очень важно, о какой ширине он говорит.
В любом случае, "общий просмотрщик" (AskGUIFn) имеет следующие типы typedef для этого:
typedef int (AskGUIFn::*MemberFn)(const GMProject::pTree& tOut, const GMProject::pTree& tIn, int) const;
typedef std::vector<std::pair<boost::regex, MemberFn> > DisplaySubMap_Ty;
typedef std::map<RESOURCE_TYPES, std::pair<DisplaySubMap_Ty, MemberFn> > DisplayMap_Ty;
Где "GMProject:: pTree" является деревом node, RESOURCE_TYPES является константой для отслеживания того, каким ресурсом я на данный момент (спрайт, объект и т.д.). "MemberFn" будет просто просто загружать виджет. (Хотя AskGUIFn, конечно, не единственный общий зритель, этот только открывается, если другие "автоматические", "перезаписать", "пропустить", переименовать обработчики не удались).
Теперь, чтобы показать, как эти карты инициализируются (все в пространстве имен "MW" является виджем qt):
AskGUIFn::DisplayMap_Ty AskGUIFn::DisplayFunctionMap_INIT() {
DisplayMap_Ty t;
DisplaySubMap_Ty tmp;
tmp.push_back(std::pair<boost::regex, AskGUIFn::MemberFn> (boost::regex("^instances "), &AskGUIFn::ExecuteFn<MW::RoomInstanceDialog>));
tmp.push_back(std::pair<boost::regex, AskGUIFn::MemberFn> (boost::regex("^code $"), &AskGUIFn::ExecuteFn<MW::RoomStringDialog>));
tmp.push_back(std::pair<boost::regex, AskGUIFn::MemberFn> (boost::regex("^(isometric|persistent|showcolour|enableViews|clearViewBackground) $"), &AskGUIFn::ExecuteFn<MW::ResourceBoolDialog>));
//etc etc etc
t[RT_ROOM] = std::pair<DisplaySubMap_Ty, MemberFn> (tmp, &AskGUIFn::ExecuteFn<MW::RoomStdDialog>);
tmp.clear();
//repeat above
t[RT_SPRITE] = std::pair<DisplaySubMap_Ty, MemberFn>(tmp, &AskGUIFn::ExecuteFn<MW::RoomStdDialog>);
//for each resource type.
Затем, когда дерево-структура данных сообщает общему зрителю, что она хочет быть отображенной, программа просмотра выполняет следующую функцию:
AskGUIFn::MemberFn AskGUIFn::FindFirstMatch() const {
auto map_loc(DisplayFunctionMap.find(res_type));
if (map_loc != DisplayFunctionMap.end()) {
std::string stack(CallStackSerialize());
for (auto iter(map_loc->second.first.begin()); iter != map_loc->second.first.end(); ++iter) {
if (boost::regex_search(stack, iter->first)) {
return iter->second;
}
}
return map_loc->second.second;
}
return BackupScreen;
}
И тут проблемы стали откровенными.Функция CallStackSerialize()
зависит от стека вызовов. Однако этот call_stack хранится внутри "обработчика". Я сохранил его там, потому что все начинается с обработчика. Я не совсем уверен, где я должен хранить этот "call_stack". Ввести еще один объект, который отслеживает, что происходит?
Я попытался перейти по маршруту, где я храню родительский элемент с самим node. (Предотвращение необходимости в стеке вызовов). Однако это не так хорошо, как хотелось бы: каждый node просто имеет вектор, содержащий его дочерние узлы. Поэтому использование указателей не может быть указано на родительскую заметку...
(PS: может быть, я должен реформировать это в другом вопросе..)