我们正在重构一个long方法;它包含一个包含多个continue语句的长continue循环。我只想使用提取方法重构,但是Eclipse的自动提取方法不知道如何处理条件分支。我也不知道。
我们的当前策略是引入一个keepGoing标志(一个实例变量,因为我们想要提取方法),在循环顶部将其设置为false,并将每个继续替换为将标志设置为true,然后将以下所有内容(在不同嵌套级别)包装到if (keepGoing)子句中。然后执行各种提取,然后用提取方法的早期返回替换keepGoing分配,然后去掉标志。
有更好的办法吗?
Update:作为对评论的回应--我不能分享代码,但这里有一个匿名摘录:
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();
}
}
}
}发布于 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子句。再试一次。此时可能会出现一些额外的优化,如果将它的逻辑与您传递的用于区分这两个调用的变量结合起来,则很可能会丢失整个优化。
继续做这样的事情然后迭代。重构的诀窍是在每个步骤之间使用非常小的步骤和测试,以确保没有任何改变。
发布于 2009-07-20 21:14:11
如果我面对您的情况,我会考虑使用其他重构技术,例如“用多态替换条件”。也就是说,您应该一次只做一件事,所以如果您首先想要提取方法,那么您有两个选项:
抛出异常
在这两个选项中,我认为keepGoing标志更好。在你提取方法之后我不会停止重构。我相信,一旦您有了一个更小的方法,您将找到一种方法来删除此标志,并具有更清晰的逻辑。
发布于 2009-07-21 15:42:56
我将在这里总结答案,同时接受比尔·K的回答,认为这是最完整的。但是每个人都有一些很好的东西,我可能会在下次面对这种情况时使用任何一种方法。
mmyers:去掉循环体,将其粘贴到一个新方法中,并将所有的continue都替换为return。这非常有效,不过如果循环中有其他控制流语句,比如“中断”和“返回”,也会有问题。
Bill K:迭代地拆开它;寻找复制并消除它。利用多态类替换条件行为。使用非常小的步骤。是的,这都是很好的建议,适用范围比这个具体案例更广。
:要么使用keepGoing标志替换continue,要么抛出异常。我没有尝试这个,但我认为例外选项是一个非常好的选择,而且是一个我没有考虑过的选择。
https://stackoverflow.com/questions/1155947
复制相似问题