我有一次面试,面试官首先问我抽象类与所有抽象方法和接口(interface)有什么区别。
我回复说以后如果要继承什么东西你已经扩展了一个类就不行了。
然后,他表示在这种情况下,永远不必扩展任何其他类,而您必须实现契约。在这种情况下,抽象类和接口(interface)哪个更好?
我告诉他你可以使用其中任何一个,但他并不满意。我不明白为什么 - 我相信这是开发人员/设计的选择。
最佳答案
声明接口(interface)表示契约的答案是 Not Acceptable 。
这就是我们给 Junior 的答案,因为如果没有太多的架构经验和阅读大量经典书籍,很难清楚地弄清楚抽象类的本质和接口(interface)的本质之间的区别。
任何具有 public
方法的抽象类都充当契约和接口(interface)。
在 99% 的情况下,不提供任何实现的抽象类代表对象的角色。
一个接口(interface)代表一个角色。
每个对象可能有几个不同的角色,这些角色不应捆绑在一起,而是由相关对象组成。
我用这个例子来解释这一点:
你的面试官可能会说:
我有一个可以走路的机器人
和一个也可以走路的人
。
所以基于这个案例,他问你:我应该在抽象基类或接口(interface)中提取行走特征,知道实现没有共同点吗?
你认为...“哦,我知道是这样:在这种情况下,拥有一个带有抽象方法 walk()
的抽象类,显然与使用 声明一个接口(interface)是一样的>walk()
方法。”
所以你的回答肯定是:“这是开发者的选择!”。
这真的不是一个总是有效的答案。
为什么?让我们看看接下来的期待:
人
可以吃东西,但显然机器人
不能吃,甚至不需要。
如果您使用抽象类实现行走功能会怎样?你最终会得到:
public abstract class Biped {
public void abstract walk();
}
public Robot extends Biped {
public void walk() {
//walk at 10km/h speed
}
}
public Human extends Biped {
public void walk() {
//walk at 5km/h speed
}
}
您如何插入eating
功能?你被困住了,因为你不能在 Biped
基类中实现它,因为它会破坏 Liskov 替换原则,因为 Robot
不会'不吃!
由于已知的 Java 规则,您不能期望 Human
扩展另一个基类。
当然,您可以添加一个专门用于 Human 的特定 Feedable 接口(interface):
public interface Feedable {
void eat();
}
签名变为:public Human extends Biped implements Feedable {
显然,让一个角色通过类实现而另一个通过接口(interface)实现是没有意义和令人困惑的。
这就是为什么只要我们有选择,就真正首选从接口(interface)开始。
有了接口(interface),我们可以通过组合轻松地对角色进行建模。
所以最终的解决方案是:
public interface Walkable {
void abstract walk();
}
public interface Feedable {
void eat();
}
public Robot implements Walkable {
public void walk() {
//walk at 10km/h speed
}
}
public Human implements Walkable, Feedable {
public void walk() {
//walk at 5km/h speed
}
public void eat(){
//...
}
}
是不是让你想起了接口(interface)隔离原则? ;)
总而言之,如果您指定IS-A 关系,则使用抽象类。 如果您意识到您将要为一个角色(假设是一个IS-CAPABLE-OF 关系)建模,请使用界面。
关于java - 抽象类与所有方法抽象和接口(interface)之间的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23302920/