Java中相同逻辑的推广方法

问题描述 投票:4回答:4

嗨,假设我们有一个包含许多数组列表的类,并包含非常类似的方法,如下所示

public class Foo {
    private ArrayList<Rapper> rapperList = new ArrayList<>();
    private ArrayList<Musician> musicianList = new ArrayList<>();
    private ArrayList<Stadium> stadiumList = new ArrayList<>();

    public List<String> getRapperName() {
        ArrayList<String> rapperNameList = new ArrayList<>();
        for (Rapper r : rapperList) {
            rapperNameList.add(r.getRapperName());
        }
        return rapperNameList;
    } 

    public List<String> getMusicianName() {
        ArrayList<String> musicianNameList = new ArrayList<>();
        for (Musician m : musicianNameList) {
            musicianNameList.add(m.getMusicianName());
        }
        return musicianNameList;
    } //done

    public List<String> getStadiumID() {
        // exactly the same as above (using same logic)
    }

}

我省略了getStadiumID方法代码,因为它与上面的代码完全相似,并且所有方法都遵循相同的逻辑:

  • 做一个列表
  • 循环通过相应的数组
  • 添加到列表中
  • 退货清单

我觉得有很多重复的代码,因为我基本上遵循相同的逻辑,并想知道是否有一种简化这些方法的方法。我在java中查看泛型,但似乎无法从中获得任何东西。

假设我的知识只适用于Java 7(大于7的任何东西,我不知道lambda等)

java generics refactoring
4个回答
2
投票

基本上,你在这里做的是映射列表中的每个元素:

return list.stream().map(fn).collect(Collectors.toList());

您可以将此包装在一个采用List<T> listFunction<T, S> fn的方法中,其中S是列表元素的类型(例如问题代码中的String)。

private static <T, S> List<S> makeList(List<T> list, Function<T, S> fn) {
  return list.stream().map(fn).collect(Collectors.toList());
}

然后你可以调用:

public List<String> getRapperName() {
  return makeList(rapperList, Rapper::getRapperName);
}

public List<String> getMusicianName() {
  return makeList(musicianList, Musician::getMusicianName);
}

您可以在Java 8之前的代码中实现它;但它不会很漂亮。

首先,您需要一个Function界面。您可以使用Guava中的一个,其他一些库;或者只是自己定义一个,如果你不想采取依赖:

interface Function<T, S> {
  S apply(T input);
}

然后定义makeList方法:

private static <T, S> List<S> makeList(List<T> list, Function<T, S> fn) {
    ArrayList<String> result = new ArrayList<>();
    for (T t : list) {
        result.add(fn.apply(t));
    }
    return result;
}

然后调用如下:

public List<String> getRapperName() {
  return makeList(rapperList, new Function<Rapper, String>() {
    @Override public String apply(Rapper r) {
      return r.getRapperName();
    }
  });
}

public List<String> getMusicianName() {
  return makeList(musicianList, new Function<Musician, String>() {
    @Override public String apply(Musician m) {
      return m.getMusicianName();
    }
  });
}

什么乱七八糟的语法。

你可以把Functions拉成常数等等,让它看起来更清晰;但老实说,你在这里有更多的代码(和那些非惯用的代码),而不仅仅是像你现在那样重复代码。


1
投票

好的......当然你可以使用泛型,但你可能需要改变一些事情....我将使用Java 7以防万一,但使用Java 8的东西可以变得更容易一些。

首先直接进入要重写的类:

public class Foo<T extends NamedObject> { 
//We will get to what is NamedObject in a moment
    private ArrayList<T> list = new ArrayList<>();

    public List<String> getNames() {
        ArrayList<String> nameList = new ArrayList<>();
        for (T r : list) {
            nameList.add(r.getName());
        }
        return nameList;
    } 
}

现在你应该能够使用这样的类,有一个小编译错误(为什么?因为我们没有了解NamedObject应该是什么):

Foo<Rapper> rapperObj = new Foo<>();
rapperObj.getNames();
Foo<Musician > musicianObj = new Foo<>();
musicianObj.getNames();

我们可以定义NamedObject(随意更改适合您的名称)作为定义一个“getName”方法的接口,并使Rapper,Musician和任何拥有名称的类实现此方法。在Rapper课程中使用“rapperName”,在音乐家课程中使用“musicianName”听起来有点多余,在Rapper中只有“名字”应该足以让每个人都像解释者的名字一样解释它(你不觉得)并且让它更容易对我们也是。

public interface NamedObject {
    String getName();
}

public class Rapper implements NamedObject {
    //Instead of rapperName put only name
    @Override
    public String getName() { ... }
    ... //All the things you have in this class
}

没有时间测试它,但这应该可以解决问题。

注意:实际上可能有另一种方法可以在没有接口的情况下解决它,使用Foo作为抽象类,并为每个对象类型提供一个子类


0
投票

在Java 8中,我们将使用lambdas。这可以在Java 7中重新编码,如下所示:

public class Foo {
    private ArrayList<Rapper> rapperList = new ArrayList<>();
    private ArrayList<Musician> musicianList = new ArrayList<>();
    private ArrayList<Stadium> stadiumList = new ArrayList<>();

    public List<String> getRapperName() {
        return asStringList(rapperList, new StringGetter<Rapper>() {
            @Override
            public String get(Rapper it) {
                return it.getRapperName();
            }
        });
    }

    public List<String> getMusicianName() {
        return asStringList(musicianList, new StringGetter<Musician>() {
            @Override
            public String get(Musician it) {
                return it.getMusicianName();
            }
        });
    }

    interface StringGetter <T> {
        String get(T it);
    }

    private <T> List<String> asStringList(List<T> list, StringGetter<T> getter) {
        List<String> stringList = new ArrayList<>();
        for(T t: list) {
            stringList.add(getter.get(t));
        }
        return stringList;   
    }

}

-1
投票

您还可以将您的类作为可用于处理任何对象的通用类(Rapper,Musician,Stadium ......)

public class GenericsDemo<T> {
private ArrayList<T> genericList = new ArrayList<>();

public ArrayList<T> getGenericList() {
    return genericList;
}

public void setGenericList(ArrayList<T> genericList) {
    this.genericList = genericList;
}

public List<String> getGenericName() {
    ArrayList<String> genericNameList = new ArrayList<>();
    for (T obj : genericList) {
        Field field = obj.getClass().getDeclaredField("name");
        Object nameValue = field.get(obj);
        genericNameList.add(nameValue );
    }
    return genericNameList;
}

}

从主类中创建此类的对象并将其用于任何类型。

class GenericsMain {
GenericsDemo<Rapper> rapperObj = new GenericsDemo<>();
//create arraylist of any object
//call the setter method
//call the getname method

}

© www.soinside.com 2019 - 2024. All rights reserved.