我有一次面试,面试官首先问我抽象类与所有抽象方法和接口(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/
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行
我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht