很长一段时间我一直在处理一个应用程序。由于编程只是一项业余爱好,这个项目已经走得太久了,但那不仅仅是重点。我现在处于一个每个“问题”变得非常难以解决的地步。我正在考虑重构代码,但是这会导致“完全”重写。编程范例;想知道是否需要重写/重构
让我解释一下这个问题,以及我目前如何解决它。基本上我有数据,而我让事情发生在这些数据上(我描述的每个程序都不是我?)。什么情况是:
数据 - >请求查看器中显示 - >查看器显示基于实际数据的数据 浏览器返回用户输入 - >数据 - >问“执行”来执行它 - >新数据
现在,这个曾经工作得很好,我本来想:“嘿,我可能例如变化的命令提示符下QT,或窗口 - 甚至采取外部(C#)和简单的调用这个程序” 。
然而随着程序的发展,它变得越来越令人厌烦。最重要的是数据以不同的方式显示,具体取决于数据是什么以及更重要的是它位于何处。所以我回到树&添加一些“跟踪”父母的线“然后,一般的观众会搜索最具体的实际小部件。 它使用了一个与[位置;小部件]值的列表,和找到最佳匹配位置
更新新“数据”时出现问题 - 我必须通过所有资产 - 查看器,保存等等。更新检查机制给了我很多错误。像“嘿为什么它现在再次显示错误的小部件?”
现在我可以完全交换这个了,而不是树数据结构调用一个普通的查看器,我会使用OO“内部”树功能。节点将是孩子(& whe ñ需要一个新的查看器或保存机制新的孩子形成)。
这将删除困难的检查机制,我检查树中的位置。然而,它可能会打开整个其他的蠕虫。 我想就此发表一些评论?我应该让观察者完全分开 - 难以检查数据吗?或者新方法更好,但它将数据执行结合到单个节点中。 (所以,如果我想从QT改变说CLI/C#变得几乎不可能)
我到底应该追求什么方法?还有什么我可以做的吗?为了保持观看者的独立性,同时又要阻止必须进行检查以查看应显示哪个小部件?
编辑,只是为了显示一些“代码”,以及我的程序如何工作。不知道这是否有什么好处,因为我已经说过它已经成为相当多的方法论。
它意味着合并几个“gamemaker项目”在一起(如GM:工作室奇怪地缺乏那个特点)。 Gamemaker项目文件只是一组xml文件。 (主xml文件只包含其他xml文件的链接,每个资源对象,精灵,声音,房间等都有一个xml文件)。然而,有一些'怪癖'使得用类似boost属性树或qt的东西阅读是不太可能的:1)属性/子节点的顺序在文件的某些部分非常重要。 2)白色空间往往被忽略,但在其他地方,保存它是非常重要的。
这就是说,也有很多点,其中节点是完全相同的。就像背景可以有<width>200</width>
和一个房间也可以有。然而,对于用户来说,他谈论的宽度是相当重要的。
不管怎么说,因此,“一般观众”(AskGUIFn)具有以下类型定义来处理这个问题:
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中”是一个树节点,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”。介绍另一个跟踪发生了什么的对象? 我尝试去存储父节点本身的路由。 (防止需要调用堆栈)。然而,这并没有如我所愿:每个节点都只有一个包含其子节点的向量。所以使用指针是没有问题的,指向父注释... (PS:也许我应该在另一个问题中改革这个..)
+1,为数字。没有阅读这个问题,它看起来很酷。 – iammilind
您是否熟悉“[内部平台效果](http://en.wikipedia.org/wiki/Inner_platform_effect)”?我不明白你的问题是否足以得出任何结论(我对你的应用一无所知),但如果你不熟悉这个术语,那么值得进行一些研究。努力修改一个旨在成为超级通用框架的非常复杂的系统听起来像是这种特定反模式的一种症状... – Rook
是不是它在创建数据节点时需要一种配置文件,配置文件描述了如何展现,行动并拯救他们? – armel