这个问题在这里已经有答案了:
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();
,一切都在编译。然而,我不确定这是否是一个好的做法。有人能帮我理解我遗漏了什么概念吗?谢谢。
2条答案
按热度按时间mpbci0fu1#
这不会编译。
您有两种选择:
尝试
List<? extends Player> getPlayers()
在你的界面上,现在你可以写了List<EspnPlayer> getPlayers()
如果这是一个有效的实现。请注意,无法调用.add()
在这个列表上,出于合理的原因(毕竟,添加一个非espnplayer到这个列表中会打破这个列表!)如果需要添加内容,那么除了:
在面向对象编程中,“编程到接口”通常被认为是最佳实践。
被动语态的使用很好,但是,正如维基百科编辑所说,[需要引用]。
这有一点道理,但与所有编程风格的建议一样,它过于简单化了。这不是一个问题,但这就是为什么下面的格言几乎总是正确的:如果你不理解风格推荐背后的原因,那么盲目地遵循它是愚蠢的,会导致更糟糕的代码。没有简单的解决方法:你必须首先考虑到建议背后的考虑因素,在此之前你不能使用建议。
anhgbhbe2#
我会做类似的事情:
您还可以在类声明中使用泛型类型参数来帮助简化它们。
但是,除非您指定您将获得哪种类型的播放器,否则您将被限制在播放器类的公共字段中。
此外,由于子类提供了新的私有字段,因此需要为它们提供getter。
最后,编程到一个像
List
并不意味着你可以改变列表的内容。这意味着您可以更改列表本身的实现。一如既往,如果您需要只有实现提供的特定特性(例如方法),则必须返回实现类型而不是接口类型。