加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 编程范例想知道是否需要重写/重构

发布时间:2020-12-16 06:45:00 所属栏目:百科 来源:网络整理
导读:在一段时间内,我一直在应用程序.由于程序设计只是一个兴趣,所以这个项目已经过时了,但这还不止这一点.我现在正处于一个“每个问题”变得非常难解决的地步.我正在考虑重构代码,但是会导致“完整”重写. 让我解释这个问题,我现在解决了什么.基本上我有数据,我
在一段时间内,我一直在应用程序.由于程序设计只是一个兴趣,所以这个项目已经过时了,但这还不止这一点.我现在正处于一个“每个问题”变得非常难解决的地步.我正在考虑重构代码,但是会导致“完整”重写.

让我解释这个问题,我现在解决了什么.基本上我有数据,我让事情发生在这些数据(我描述的每个程序没有我吗?).会发生什么?

Data -> asks viewer to display -> viewer displays data based on actual data
viewer returns user input -> data -> asks “executor” to execute it -> new data

现在这个工作非常好,我原本以为“我可以用qt或windows来改变命令提示符,或者甚至把外部的(C#),直接调用这个程序”.

然而,随着方案的成长,它变得越来越麻烦了.最重要的是,数据以不同的方式显示,取决于数据是什么,更重要的是它位于何处.所以我回到树上添加到“追踪”父行是什么“,然后一般查看器将搜索最具体的实际小部件.
它使用的列表有[位置;小部件]值,并找到最匹配的位置.

更新新的“数据”时,问题开始 – 我必须通过所有的资源 – 查看器,保护程序等等.更新检查机制给了我很多错误..像“嘿,为什么它显示错误的小部件现在呢?“

现在我可以完全互换这个.而不是树数据结构调用一般的查看器.我将使用OO“内部”树功能.节点将是子节点(当需要新的观察者或节点机制时,形成新的子节点).

这将消除困难的检查机制,其中我检查树中的位置.然而,它可能会打开一个其他的蠕虫病毒.
我想对此有一些意见?我应该保持观众完全分离 – 难以检查数据吗?或者更好的是新的方法,但它结合了数据和执行到单个节点. (所以如果我想从qt改为说cli / C#几乎是不可能的)

最后我应该采取什么方法?还有什么我可以做的吗?为了保持观众分开,但是防止不必做检查,看看应该显示哪个小部件?

编辑,只是为了显示一些“代码”和我的程序如何工作.不知道这是否有好处,因为我已经说过,它已经成为相当多的方法论.

这意味着要合并几个“gamemaker项目”(因为GM:工作室奇怪地缺乏这个功能). Gamemaker项目文件只是一组xml文件. (主XML文件,其中只包含其他xml文件的链接,每个资源的对象,精灵,声音,房间等)的xml文件.然而,有一些“怪癖”使得它不可能用boost属性树或qt来读取:1)属性/子节点的顺序在文件的某些部分是非常重要的.和2)白色空间经常被忽略,但在其他方面,保存它是非常重要的.

就这样说,节点完全一样,还有很多点.像背景一样,< 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”是一个树节点,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:也许我应该在另一个问题上改革这个)

解决方法

将这种复杂的位置检查机制重新构建/重写成一个专门的类,这样就可以改进你的解决方案,而不会影响程序的其余部分.让我们称之为NodeToWidgetMap.

建筑
看起来你的朝向Model-View-Controller架构,这是一件好事IMO.您的树结构及其节点是模型,其中观察者和“小部件”是视图,而根据节点的逻辑选择小部件将成为控制器的一部分.

主要问题是什么时候和如何选择给定节点N的小部件wN以及如何存储此选择.

NodeToWidgetMap:何时选择
如果您可以假设wN在其生命周期内不会改变,即使节点被移动,您可以在创建节点时选择它.否则,您将需要知道位置(或通过XML的路径),因此,在请求节点时可以查找节点的父节点.

查找父节点
我的解决方案是存储指针而不是节点实例本身,也许使用boost :: shared_ptr.这有缺点,例如复制节点强制您实现自己的复制构造函数,它使用递归来创建子树的深层副本. (移动不会影响子节点.)

存在替代方案,例如,每当触及祖父向量的父节点时,保持子节点更新.或者您可以定义Node :: findParentOf(node)函数,知道某些节点只能(或经常)被发现为某些节点的子节点.这是野蛮的,但是对于小树木来说,工作相当不错,只是不能很好地扩展.

NodeToWidgetMap:如何选择
尝试写下规则如何选择wN在纸上,也许只是部分.然后尝试将这些规则翻译成C.这可能会在代码方面稍长一些,但会更容易理解和维护.

您当前的方法是使用正则表达式来匹配XML路径(堆栈).

我的想法是创建一个查找图,其边缘由XML元素名称标记,其节点指示应使用哪个窗口小部件.这样您的XML路径(堆栈)将描述通过图形的路径.那么问题就变成是明确地建模一个图形,还是一组函数调用是否可以用来镜像这个图.

NodeToWidgetMap:存储选择的位置
将唯一的数字标识与每个节点相关联,使用NodeToWidgetMap中的节点ID到窗口小部件的地图记录窗口小部件选择.

重写与重构
如果您重写,您可能会获得良好的杠杆效应,将其绑定到现有的Qt框架,以便专注于您的程序,而不是重写轮子.将一个编写好的程序从框架移植到另一个框架可以更容易,而不是围绕每个平台的特征进行抽象. Qt是获取经验和对MVC架构的良好理解的一个很好的框架.

完全重写可以让您有机会重新思考一切,但意味着您从头开始的风险,并且将在没有新版本的情况下,花费大量时间.谁知道你是否有足够的时间完成?如果您选择重构现有的结构,那么您将逐步改进,在每一步后都可以使用可用的版本.但是,以旧的思维方式仍然存在很小的风险,因为重写几乎迫使你重新思考一切.所以这两种方法都有其优点,如果你喜欢编程,我会重写.更多的编程,更多的快乐.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读