首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >连续提取法

连续提取法
EN

Stack Overflow用户
提问于 2009-07-20 21:04:20
回答 3查看 2.1K关注 0票数 5

我们正在重构一个long方法;它包含一个包含多个continue语句的长continue循环。我只想使用提取方法重构,但是Eclipse的自动提取方法不知道如何处理条件分支。我也不知道。

我们的当前策略是引入一个keepGoing标志(一个实例变量,因为我们想要提取方法),在循环顶部将其设置为false,并将每个继续替换为将标志设置为true,然后将以下所有内容(在不同嵌套级别)包装到if (keepGoing)子句中。然后执行各种提取,然后用提取方法的早期返回替换keepGoing分配,然后去掉标志。

有更好的办法吗?

Update:作为对评论的回应--我不能分享代码,但这里有一个匿名摘录:

代码语言:javascript
复制
private static void foo(C1 a, C2 b, C3 c, List<C2> list, boolean flag1) throws Exception {
    for (int i = 0; i < 1; i++) {
        C4 d = null;
        Integer e = null;
        boolean flag2 = false;
        boolean flag3 = findFlag3(a, c);
        blahblahblah();
        if (e == null) {
            if (flag1) {
                if (test1(c)) {
                    if (test2(a, c)) {
                        Integer f = getF1(b, c);
                        if (f != null)
                            e = getE1(a, f);
                        if (e == null) {
                            if (d == null) {
                                list.add(b);
                                continue;
                            }
                            e = findE(d);
                        }
                    } else {
                        Integer f = getF2(b, c);
                        if (f != null)
                            e = getE2(a, f);
                        if (e == null) {
                            if (d == null) {
                                list.add(b);
                                continue;
                            }
                            e = findE(d);
                        }
                        flag2 = true;
                    }
                } else {
                    if (test3(a, c)) {
                        Integer f = getF2(b, c);
                        if (f != null)
                            e = getE2(a, f);
                        if (e == null) {
                            if (d == null) {
                                list.add(b);
                                continue;
                            }
                            e = findE(d);
                        }
                        flag2 = true;
                    } else {
                        if (d == null) {
                            list.add(b);
                            continue;
                        }
                        e = findE(d);
                        flag2 = true;
                    }
                }
            }
            if (!flag1) {
                if (d == null) {
                    list.add(b);
                    continue;
                }
                e = findE(d);
            }
        }
        if (e == null) {
            list.add(b);
            continue;
        }
        List<C2> list2 = blahblahblah(b, list, flag1);
        if (list2.size() != 0 && flag1) {
            blahblahblah();
            if (!otherTest()) {
                if (yetAnotherTest()) {
                    list.add(b);
                    continue;
                }
                blahblahblah();
            }
        }
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-07-20 21:47:09

这是其中一个有趣的地方,没有单一的模式会让你去那里。

我会反复努力。

首先,我会试着看看我是否能用一个早期继续删除其中一个级别的ifs。与深度嵌套的ifs相比,检查条件并尽早返回(在您的情况下是继续)的代码要清晰得多。

接下来,我想我会取一些内部块,看看它们是否能被提取成一个单独的方法。它看起来像前两个大块(在"if (test2(a,c)) {“和它的else语句中)非常相似。有剪切和粘贴逻辑,应该是相同的。

最后,在清理完这些东西之后,你可以开始研究你的实际问题--你需要更多的课程。整个语句可能是3-5兄弟类中的三行多态方法。

它非常接近于丢弃和重写代码,一旦您确定了实际的类,整个方法就会消失,并被一些非常简单的东西所取代。事实上,它是一个静态实用程序,它应该告诉你一些事情--你不想在这种类型的代码中出现这样的情况。

编辑(再看一看):这里有很多东西,所以很有趣。记住,当您完成任务时,您不希望代码重复--我非常肯定,这整件事情可以在没有一个if的情况下编写--我认为所有的ifs都是可以/应该通过多态处理的情况。

哦,作为对eclipse不想做的问题的一个回答--甚至不要尝试用这个自动重构,只需手工完成。第一个if()中的内容需要被提取到一个方法中,因为它实际上与它的its ()中的子句完全相同!

当我这样做时,我通常创建一个新方法,将代码从if移到新方法中(只在if中留下一个对新方法的调用),然后运行一个测试并确保没有破坏任何东西。

然后逐行检查,以确保if和它的其他代码之间没有区别。如果存在,则通过将差异作为新变量传递给方法来补偿它。在您确定所有内容都相同之后,请用call替换else子句。再试一次。此时可能会出现一些额外的优化,如果将它的逻辑与您传递的用于区分这两个调用的变量结合起来,则很可能会丢失整个优化。

继续做这样的事情然后迭代。重构的诀窍是在每个步骤之间使用非常小的步骤和测试,以确保没有任何改变。

票数 9
EN

Stack Overflow用户

发布于 2009-07-20 21:14:11

如果我面对您的情况,我会考虑使用其他重构技术,例如“用多态替换条件”。也就是说,您应该一次只做一件事,所以如果您首先想要提取方法,那么您有两个选项:

  1. 添加"keepGoing“标志
  2. 从方法

抛出异常

在这两个选项中,我认为keepGoing标志更好。在你提取方法之后我不会停止重构。我相信,一旦您有了一个更小的方法,您将找到一种方法来删除此标志,并具有更清晰的逻辑。

票数 2
EN

Stack Overflow用户

发布于 2009-07-21 15:42:56

我将在这里总结答案,同时接受比尔·K的回答,认为这是最完整的。但是每个人都有一些很好的东西,我可能会在下次面对这种情况时使用任何一种方法。

mmyers:去掉循环体,将其粘贴到一个新方法中,并将所有的continue都替换为return。这非常有效,不过如果循环中有其他控制流语句,比如“中断”和“返回”,也会有问题。

Bill K:迭代地拆开它;寻找复制并消除它。利用多态类替换条件行为。使用非常小的步骤。是的,这都是很好的建议,适用范围比这个具体案例更广。

:要么使用keepGoing标志替换continue,要么抛出异常。我没有尝试这个,但我认为例外选项是一个非常好的选择,而且是一个我没有考虑过的选择。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1155947

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档