Dan*_*ush 6 java oop abstract-class interface
我接受采访时,面试官首先问我抽象类与抽象方法和界面之间的区别.
我回答说,如果将来要求继承某些内容,如果你已经扩展了课程,那么你将无法继续.
然后,他说这是一种情况,人们永远不必延长任何其他阶级,你必须实施合同.在这种情况下,哪个更好,一个抽象类或接口?
我告诉他你可以使用其中任何一个,但他不满意.我无法理解为什么 - 我相信这是开发人员/设计选择.
说明接口代表合同的答案是不可接受的.这就是我们给Junior的答案,因为它可能很复杂,可以清楚地弄清楚抽象类的本质与界面的本质之间的区别,而没有太多的架构经验,也没有阅读很多经典书籍.任何带public
方法的抽象类都可以作为契约和接口.
在99%的情况下,不提供任何实现的抽象类是对象角色的表示.
一个接口表示角色.
每个对象可能有几个不同的角色,这些角色不应该绑定在一起,而是由相关对象组成.
我用这个例子解释这个:
你的面试官可以说:
我有一个Robot
可以走路,Human
也可以走路.
所以基于这种情况,他问你:我应该在抽象基类或界面中提取步行特征,知道实现没有任何共同之处吗?
你认为......"哦,我知道:在这种情况下,有一个带抽象方法的抽象类walk()
,那么显然与声明该walk()
方法的接口相同."
所以你的答案肯定是:"这是开发人员的选择!".
这真的不是一个永远有效的答案.
为什么?让我们看看下一个期望:
A Human
可以吃,但显然Robot
不能,甚至不需要.
如果您使用抽象类实现了行走功能,该怎么办?你会最终得到:
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
}
}
Run Code Online (Sandbox Code Playgroud)
你怎么能插上这个eating
功能?你被卡住是因为你不能在Biped
基类中实现它,因为它会打破Liskov Substitution Principle,因为Robot
它不会吃!而且Human
由于已知的Java规则,您不能指望扩展另一个基类.
当然,您可以添加仅专用于Human的特定Feedable界面:
public interface Feedable {
void eat();
}
Run Code Online (Sandbox Code Playgroud)
签名变为:public Human extends Biped implements Feedable {
显然,通过一个类实现一个角色而通过一个接口实现另一个角色是没有意义和困惑的.
这就是为什么每当我们有选择时,首先选择接口是首选.
通过界面,我们可以通过编写轻松地为角色建模.
那么最终的解决方案是:
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(){
//...
}
}
Run Code Online (Sandbox Code Playgroud)
它不提醒您接口隔离原则吗?;)
总而言之,如果指定IS-A关系,则使用抽象类.如果您意识到您要为角色建模(假设是一个IS-CAPABLE-OF关系),请使用界面.