新手区 多维度分析:抽象类和接口的区别

OneAPM官方技术博客 · 2015年09月15日 · 最后由 陈恒捷 回复于 2015年09月15日 · 1797 次阅读

【编者按】本文作者是Sebastian Malaca,是面向对象编程的狂热者,不断深化研究整洁代码和高代码质量。本文中,作者通过多个方面深入剖析抽象类和接口的区别,并结合经验供读者借鉴学习,本文系 OneAPM 工程师编译整理。

在开发人员岗位面试时,是否了解抽象类和接口之间的基本区别是一个很重要的考量因素。

显而易见?

完全不是。笔者面试过很多人,通常问的第一个问题是关于接口和抽象类的区别。但实际上很少有程序员能给出正确的答案。

就这个问题来说,初级程序员可能都会清楚之间的区别,可能也并不一定理解其背后的原因,但其结构上的差异,特别是针对特定语言(几乎和所有的面向对象的语言一样)应该深入了解。

同时,笔者也发现其他职位候选人(有时甚至是高级职位)竟然也不知道这之间的差异,或者只知道的一个或几个。

如果只是需要了解这些内容那并不难,但这些都是面向对象的基础知识,因此想要设计良好的代码必须对其有一个深入的认识。

下面将详细介绍这些基础知识。

继承

下面将从众所周知的接口和抽象类的区别开始。这种差异是关于继承的,任何类都可以实现多个接口,但是只能扩展一个类,也只能有一个父类。

多个类扩展是一个语言特性,它存在于一些面向对象的语言。为什么呢?因为它带来的问题往往多于价值。

当一个类有许多父类时,有一个情况就是完全相同的方法会声明多个,因此必须显式地「告知」究竟需要的是哪一个。

这样的代码通常难以维护,因为对其进行的任何修改或者重构都必须小心地检查。另一方面,如果一个类需要扩展(至少)两个拥有相同方法的类,那么 DRY 规则显然会被破坏 (因此需要从别处下手),或者说会干扰到 Single Responsibility Principle (SAP)。

「如果多个类的继承如此糟糕,为什么它可以实现许多接口呢?」——如果这样的问题在你的脑海盘旋,我不得不承认这是一个绝妙的问题。

然而,答案很简单。每一个接口都是基于函数而不是一个类去实现。所以,即使实现十个不同的接口,每个包含相同的方法声明,内部也不会发生冲突。接口保证了方法的存在,而不是去说明方法的实现,这意味着,只要不违反 SRP ,你完全可以实现多个接口。

方法的可见度

接口中的所有方法都是 Public 的,但对于抽象类的声明并没有这样的规则,当然不能是 Private 。为什么不能 Private?因为一个抽象方法需要在子类中实现,但 Private 无法访问子类,因此不抽象类不可能存在 Private 属性。

接着回归主题。正如上文写道的,接口是一个函数的保证,你可以把它当作使用接口的类和实现这个接口的类之间的一个合约——保证一个特定类将实现所有声明的方法。这也是为什么这些方法必须是 Public 的原因。因为被严格的限制到了实现上,所以其他一切都不成问题。

然而,当涉及到抽象类时并非这样。我们总是可以有不同的类组,除了这几方面基本上不同以外,其他地方几乎一样,类体的公共方法也是非常相似的。在这种情况下,可以创建 Protected 方法来保持类之间的差异。Template Method 就是一个很典型的例子。

声明和定义

接口只能包含方法声明,而抽象类还可以包含方法的定义。

接口的重点在于提供特定函数,而抽象类还在于子类实现的相似性,不仅仅是其中的函数。

常量

接口和抽象类中都可以定义常量。这是因为这些值不依赖于特定对象,对它们来说都是相同的。

属性

抽象类可以包含属性,但接口却不能。原因与声明和定义是一样的。

总结

除了说明差异,笔者也试图解释它产生的原因。这不仅是因为人们发明某个语言时的突发奇想,而是源于语言背后所支撑的理念。

原文链接:Differences Between Abstract Class and Interface

OneAPM 是应用性能管理领域的新兴领军企业,能帮助企业用户和开发者轻松实现:缓慢的程序代码和 SQL 语句的实时抓取。想阅读更多技术文章,请访问 OneAPM 官方博客

共收到 3 条回复 时间 点赞

赞赞赞!!! 最近正在思考这些东西呢!!!

不错的文章

赞!说的十分透彻。理念方面的东西要说清楚、说全面相当不容易。

PS:有个小建议:

接口中的所有方法都是 Public 的,但对于抽象类的声明并没有这样的规则,当然不能是 Private 。为什么不能 Private?因为一个抽象方法需要在子类中实现,但 Private 无法访问子类,因此不抽象类不可能存在 Private 属性。

这句翻译读起来怪怪的。去看了原文后发现有些地方翻译不是很合适:

All methods in the interface are public, but there is no such rule for those declared in abstract classes. Those ones can have any visibility except private. Why not private? Because an abstract method needs to be implemented in subclass and private is not accessible from subclass. As you can see, those two ideas are mutually exclusive.

大致意思是抽象类不需要像接口那样都是 Public 的。它们可以是 Private 外的任何可访问权限。为啥不能是 Private ,因为抽象类需要在子类中实现,而 Private 是不能被子类访问的。因此,Private 与抽象类的用法是互斥的。

译文中的 因此不抽象类不可能存在 Private 属性 这里第一个 “不” 字应该是写多了。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册