1

我现在已经在 3 个不同的场合遇到过这种情况。大多数时候重构一些代码。

可以说我有:

//code block A
List<Bar> foo = doSomething(inputParams);
//code block B

现在,我需要这样refactor的代码,以便我想使用doSomething()方法的过程来do something else too. 可以说,也创建一个地图(Bar.id -> 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
4

2 回答 2

3

您正在返回不同的数据结构..

List<Bar> foo = doSomething(inputParams);
Map<Integer,String> foobar = doSomethingDifferent(inputParams); 

你确定他们做类似的事情吗?如果是这样,您可以提取公共部分或更改它们以返回相同的类型,然后很容易看到您可以做什么来避免重复代码。

于 2013-08-06T13:14:58.887 回答
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 将通过闭包来简化它。

解决问题的另一种方法是使用一种方法的输出从中派生另一个版本。

例如(与您发布的非常相似)

List<Bar> bars = createBarList(inputParams); // doSomething
Map<Integer,String> foobar = deriveMap(bars); // doSomethingSimilar

wherederiveMap只会遍历列表并创建地图。这就是现在这段代码所在的地方

for(Bar b: input) 
    ret.put(b.getId(),b.getName());

这些方法的作用以及如何使用它们最终取决于您。方法的名称可以帮助表达意图并帮助正确使用它们。当您不知道源代码时,不要通过将功能合并到行为不可预测的神奇函数来放弃这一点。

另一件事:更广泛的重构通常可以摆脱奇怪的结构。也许您可以将整个(Bars 列表和地图)封装到它自己的类中。专门的数据结构通常很适合从使用它们的类中移出。负责处理地图和事物列表的类可以被视为负责做不止一件事 ->单一职责原则

于 2013-08-06T14:29:42.127 回答