Java中相同逻辑的泛化方法

Java中相同逻辑的泛化方法,java,generics,refactoring,Java,Generics,Refactoring,假设我们有一个类,它包含许多数组列表,并且包含非常类似的方法,如下所示 public class Foo { private ArrayList<Rapper> rapperList = new ArrayList<>(); private ArrayList<Musician> musicianList = new ArrayList<>(); private ArrayList<Stadium> stadiu

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

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)
    }

}
公共类Foo{
private ArrayList rapperList=new ArrayList();
private ArrayList musicianList=新ArrayList();
private ArrayList statiumlist=new ArrayList();
公共列表getRapperName(){
ArrayList rapperNameList=新建ArrayList();
对于(说唱歌手r:说唱歌手列表){
rappername list.add(r.getRapperName());
}
返回说唱歌手名单;
} 
公共列表getMusicianName(){
ArrayList musicianNameList=新的ArrayList();
对于(音乐家m:音乐家名单){
添加(m.getMusicianName());
}
返回音乐家名单;
}//完成
公共列表getStadiumID(){
//与上述完全相同(使用相同的逻辑)
}
}
我省略了getStadiumID方法代码,因为它与上面的方法非常相似,并且所有方法都遵循相同的逻辑:

  • 列一张清单
  • 循环通过相应的数组
  • 添加到列表中
  • 返回列表
我觉得有很多重复的代码,因为我基本上遵循相同的逻辑,并且想知道是否有一种方法可以将这些方法简化为一种。我在研究java中的泛型,但似乎无法从中得到任何东西


假设我的知识仅限于Java 7(7以上的任何内容我都不知道lambdas等)

本质上,您在这里所做的是映射列表中的每个元素:

return list.stream().map(fn).collect(Collectors.toList());
您可以将其包装在采用
列表
函数fn
的方法中,其中
S
是列表元素的类型(例如问题代码中的
字符串

然后定义
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;
}
私有静态列表makeList(列表,函数fn){
ArrayList结果=新建ArrayList();
对于(T:列表){
结果.add(fn.apply(t));
}
返回结果;
}
然后像这样调用:

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

public List<String> getMusicianName() {
  return makeList(musicianList, Musician::getMusicianName);
}
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();
    }
  });
}
public List getRapperName(){
返回makeList(rapperList,新函数(){
@覆盖公共字符串应用(说唱歌手r){
返回r.getRapperName();
}
});
}
公共列表getMusicianName(){
返回makeList(musicianList,新函数(){
@覆盖公共字符串应用(m){
返回m.getMusicianName();
}
});
}
多么混乱的语法啊


您可以通过将
函数
s拉出为常量等方式使其看起来更干净一些;但老实说,这里有更多的代码(以及非惯用代码),而不仅仅是像现在这样复制代码。

您还可以将类作为通用类,用于处理任何对象(说唱歌手、音乐家、体育场……)

public类GenericsDemo{
private ArrayList genericList=新建ArrayList();
公共阵列列表getGenericList(){
返回泛型列表;
}
public void setGenericList(ArrayList genericList){
this.genericList=genericList;
}
公共列表getGenericName(){
ArrayList genericNameList=新的ArrayList();
对于(目标:通用列表){
Field=obj.getClass().getDeclaredField(“名称”);
对象名称值=field.get(obj);
genericNameList.add(名称值);
}
返回genericNameList;
}
}

从main类创建该类的对象,并将其用于任何类型

class GenericsMain {
GenericsDemo<Rapper> rapperObj = new GenericsDemo<>();
//create arraylist of any object
//call the setter method
//call the getname method
类GenericsMain{
GenericsDemo rapperbj=新的GenericsDemo();
//创建任意对象的arraylist
//调用setter方法
//调用getname方法

}在Java8中,我们将使用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;   
    }

}
公共类Foo{
private ArrayList rapperList=new ArrayList();
private ArrayList musicianList=新ArrayList();
private ArrayList statiumlist=new ArrayList();
公共列表getRapperName(){
return asStringList(说唱歌手列表,新的StringGetter(){
@凌驾
公共字符串获取(说唱歌手it){
返回它。getRapperName();
}
});
}
公共列表getMusicianName(){
return asStringList(音乐大师,新StringGetter(){
@凌驾
公共字符串获取(它){
返回它。getMusicianName();
}
});
}
界面吸音器{
字符串get(T it);
}
私有列表asStringList(列表列表,StringGetter){
List stringList=新建ArrayList();
对于(T:列表){
stringList.add(getter.get(t));
}
返回字符串列表;
}
}

好的。。。当然你可以使用泛型,但是你可能需要改变一些事情。。。。我将使用Java7以防万一,但使用Java8可以让事情变得简单一些

首先直接转到要重写的类:

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;
    } 
}
没有时间测试它,但这应该可以做到


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

对不起,我应该说清楚,但我只知道java 7(包括)而不知道java 8(lamdas等)。为什么您目前的知识水平排除了这个答案?你通过展示和尝试新事物获得新知识!只是我现在正在学习面向对象的设计课程,我们的讲师禁止我们学习高于7的任何东西,因为这会让我们从面向对象编程(OOP)中吸取更多的东西,而本课程没有。这个问题是在我编写代码的时候提出来的,我觉得我在重复我自己,在囤积互联网之后我真的无法回答这个问题,所以我就在这里。本质上,对于Java 8之前的代码,您无法更轻松地完成您想做的事情:它无法通用化,因为从对象获取名称的方法在每个方法中都是不同的。你可以用,
class GenericsMain {
GenericsDemo<Rapper> rapperObj = new GenericsDemo<>();
//create arraylist of any object
//call the setter method
//call the getname method
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;   
    }

}
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;
    } 
}
Foo<Rapper> rapperObj = new Foo<>();
rapperObj.getNames();
Foo<Musician > musicianObj = new Foo<>();
musicianObj.getNames();
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
}