我现在已经在3个不同的场合遇到过这种情况。大多数时候重构一些代码。
让我说我有:
//code block A
List<Bar> foo = doSomething(inputParams);
//code block B
现在,我需要refactor
代码,以便我将doSomething()
方法的流程用于do something else too
。可以说,也创建一个地图(Bar.id - &gt; Bar.name)。
有没有一种优雅的方法可以在不将可变映射传递给doSomething()而不将代码复制到另一个doSomethingDifferent()
的情况下执行此操作?
虚拟实施:
doSomething(){
List<Bar> ret = new ArrayList<Bar>();
while(//condition){
ret.add(new Bar());
}
returrn ret;
}
doSomethingDifferently(){
Map<Integer, String> ret = new HashMap<Integer, String>();
while(//condition){
Bar b = new Bar()
ret.put(b.getId(),b.getName());
}
returrn ret;
}
有没有比下面可能解决方案更好的方法?
解决方案1 :(重复代码)
List<Bar> foo = doSomething(inputParams);
Map<Integer,String> foobar = doSomethingDifferent(inputParams); //Very similar to doSomething
解决方案2 :(难以阅读)
Map<Integer,String> foobar = new HashMap<Integer,String>();
List<Bar> foo = doSomething(inputParams, foobar); //mutate the map
答案 0 :(得分:3)
您正在返回不同的数据结构..
List<Bar> foo = doSomething(inputParams);
Map<Integer,String> foobar = doSomethingDifferent(inputParams);
你确定他们做了类似的事吗?如果是这样,您可以提取公共部分或更改它们以返回相同的类型,之后很容易看出您不能重复代码。
答案 1 :(得分:1)
您的示例方法所做的不同,具有不同的方法名称。例如。 createListFrom(param)
,createMapFrom(param)
。将它与同名相结合只会令人困惑。而且我不会指望调用doSomething
并且doSomethingElse
在另一个地方重复。更广泛的概念可能会重复。
解决此问题的一种方法是将重复代码移动到另一个方法中。相同/相似的代码是
while(condition) {}
Bar b = new Bar()
b
添加到某种集合中。您的方法的通用版本可能看起来像
private void doSomethingGeneric(? param, GenericWayToHandle handler) {
while (condition) {
Bar b = createBar();
handler.doSomethingWith(b);
}
}
“简短”示例如何实现
public List<Object> doSomethingList(int param) {
ListHandler handler = new ListHandler();
doSomethingGeneric(param, handler);
return handler.list;
}
public Map<Object, Object> doSomethingMap(int param) {
MapHandler handler = new MapHandler();
doSomethingGeneric(param, handler);
return handler.map;
}
private void doSomethingGeneric(int param, CollectionHandler handler) {
for (int i = 0; i < param; i++) {
handler.handle("Hello");
}
}
private interface CollectionHandler {
void handle(String string);
}
private static class MapHandler implements CollectionHandler {
public final Map<Object, Object> map = new HashMap<Object, Object>();
@Override
public void handle(String string) {
map.put(string, string);
}
}
private static class ListHandler implements CollectionHandler {
public final List<Object> list = new ArrayList<Object>();
@Override
public void handle(String string) {
list.add(string);
}
}
遗憾的是,对于每种情况都很难处理,Java 8将通过闭包简化它。
解决问题的另一种方法是使用一种方法的输出从中派生另一个版本。
e.g。 (非常类似于你发布的内容)
List<Bar> bars = createBarList(inputParams); // doSomething
Map<Integer,String> foobar = deriveMap(bars); // doSomethingSimilar
其中deriveMap
将迭代列表并创建地图。这就是现在这段代码的地方
for(Bar b: input)
ret.put(b.getId(),b.getName());
最终由您决定这些方法的用途以及如何使用它们。方法的名称可以帮助表达意图和意图。帮助正确使用它们。不要通过将功能合并到不知道源代码时行为不可预测的神奇函数来放弃。
另外一件事:更广泛的重构通常可以摆脱奇怪的结构。也许你可以将整个(列表和条形图)封装到它自己的类中。专门的数据结构通常是一个很好的候选者,可以从一个使用它们的类中移出。负责处理地图和事物清单的类可以被视为负责做多件事 - &gt; Single responsibility principle