如何在接口方法中使用协变返回类型和列表?

4dc9hkyq  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(330)

这个问题在这里已经有答案了

list是list的一个子类吗?为什么java泛型不是隐式多态的(19个答案)
18天前关门了。
在面向对象编程中,“编程到接口”通常被认为是最佳实践。因为一个接口可以有许多实现,所以我们应该能够轻松地将一个实现替换为另一个实现。但是,当接口方法的返回类型是列表时,我很难理解如何做到这一点。
例如,假设我需要获得有关nba(篮球)球员的数据。这一数据的两个提供者可能是espn和雅虎。espn和雅虎都将提供玩家的特定领域,比如他们的 name . 不过,espn有关于这位球员的信息 college 雅虎没有。雅虎可能有关于玩家的信息 age espn没有。

public abstract class Player {
  private String name;
}
public class EspnPlayer extends Player {
  private String college;
}
public class YahooPlayer extends Player {
  private int age;
}

我希望能够在espn和yahoo提供商之间进行交换,所以我编写了一个带有实现的接口。
客户代码:

public class PlayerController {

  public List<Player> getPlayers() {
    NbaService nbaService = new EspnServiceImpl(); // or YahooServiceImpl
    return nbaService.getPlayers();
  }
}

接口和实现:

public interface NbaService {
  List<Player> getPlayers();
}
public class EspnServiceImpl implements NbaService {

  @Override
  public List<EspnPlayer> getPlayers() {
    List<EspnPlayer> espnPlayers = new ArrayList<>();
    // call ESPN API and get ESPN players
    return espnPlayers;
  }
}

这不会编译。我认为这是可行的,因为协变的返回类型。现在如果我把接口方法改为 List<? extends Player> getPlayers(); ,一切都在编译。然而,我不确定这是否是一个好的做法。有人能帮我理解我遗漏了什么概念吗?谢谢。

mpbci0fu

mpbci0fu1#

这不会编译。
您有两种选择:
尝试 List<? extends Player> getPlayers() 在你的界面上,现在你可以写了 List<EspnPlayer> getPlayers() 如果这是一个有效的实现。请注意,无法调用 .add() 在这个列表上,出于合理的原因(毕竟,添加一个非espnplayer到这个列表中会打破这个列表!)
如果需要添加内容,那么除了:

interface NbaService<T extends Player> {
    public List<T> getPlayers();
}

在面向对象编程中,“编程到接口”通常被认为是最佳实践。
被动语态的使用很好,但是,正如维基百科编辑所说,[需要引用]。
这有一点道理,但与所有编程风格的建议一样,它过于简单化了。这不是一个问题,但这就是为什么下面的格言几乎总是正确的:如果你不理解风格推荐背后的原因,那么盲目地遵循它是愚蠢的,会导致更糟糕的代码。没有简单的解决方法:你必须首先考虑到建议背后的考虑因素,在此之前你不能使用建议。

anhgbhbe

anhgbhbe2#

我会做类似的事情:

List<ESPNPlayers> p = getPlayers();

  @Override
  public <T extends Players> List<T> getPlayers() {
    List<T> players = new ArrayList<>();
    // call ESPN API and get ESPN players
    return players;
  }
}

您还可以在类声明中使用泛型类型参数来帮助简化它们。
但是,除非您指定您将获得哪种类型的播放器,否则您将被限制在播放器类的公共字段中。
此外,由于子类提供了新的私有字段,因此需要为它们提供getter。
最后,编程到一个像 List 并不意味着你可以改变列表的内容。这意味着您可以更改列表本身的实现。一如既往,如果您需要只有实现提供的特定特性(例如方法),则必须返回实现类型而不是接口类型。

相关问题