抽象类,接口和何时使用它们之间有什么区别


15

最近,我开始全神贯注于OOP,现在到了这样的地步,我越了解抽象类和接口之间的差异,就越会感到困惑。到目前为止,都无法实例化。接口或多或少是结构的蓝图,它们通过能够部分实现代码来确定骨架和摘要是否不同。

我想通过我的具体情况了解更多有关这些的信息。这是我第一个问题的链接,如果您需要更多背景信息:新班级的良好设计模型是什么?

这是我创建的两个类:

class Ad {
    $title;
    $description
    $price;

    function get_data($website){  }

    function validate_price(){  }
 }


class calendar_event {
    $title;
    $description

    $start_date;

    function get_data($website){ //guts }

    function validate_dates(){ //guts }
 }

因此,如您所见,这些类几乎是相同的。这里没有显示,但也有其他的功能,like get_zip()save_to_database()跨越我的课是常见的。我还添加了其他类“汽车”和“宠物”,这些类具有所有常用方法,并且当然具有这些类的特定属性(例如,里程,重量)。

现在,我违反了DRY原则,并且正在多个文件中管理和更改相同的代码。我打算开设更多课程,例如船,马或其他。

那么这是我要使用接口或抽象类的地方吗?根据我对抽象类的了解,我将使用超类作为模板,并将所有常见元素内置到抽象类中,然后仅添加将来类中特别需要的项目。例如:

abstract class content {
    $title;
    $description


    function get_data($website){  }

    function common_function2() { }
    function common_function3() { }
 }


class calendar_event extends content {

    $start_date;

    function validate_dates(){  }
 }

还是我会使用一个接口,并且因为它们是如此相似,所以会创建一个结构,以使每个子类出于完整性的原因而不得不使用,然后由最终开发人员负责,后者负责充实该类以对每个子类负责甚至常见功能的细节。我的想法是,将来可能需要针对特定​​班级的需求对某些“通用”功能进行调整。

尽管有上述所有内容,但如果您认为我完全误解了抽象类和接口的含义和原因,则务必让一个有效的答案停止朝这个方向思考,并提出前进的正确方法!

谢谢!


在线上有很多很好的例子。我认为这是其中之一。javapapers.com/core-java/abstract-and-interface-core-java-2/…–
Siva

Answers:


26

用外行的话来说:

接口用于“可以/可以视为”类型的关系。

抽象(以及具体的)类是针对“是”一种关系的。

看下面的例子:

class Bird extends Animal implements Flight;
class Plane extends Vehicle implements Flight, AccountableAsset;
class Mosquito extends Animal implements Flight;
class Horse extends Animal;
class RaceHorse extends Horse implements AccountableAsset;
class Pegasus extends Horse implements Flight;

BirdMosquitoHorse Animals。它们是相关的。他们从Animal继承了通用方法eat(), metabolize() and reproduce()。也许他们重写了这些方法,给它们增加了一些额外的东西,但是它们利用了Animal中实现的默认行为,例如metabolizeGlucose().

Plane是没有关系的BirdMosquitoHorse

Flight由不相似,不相关的类(例如Bird和)实现Plane

AccountableAsset也由不相似,不相关的类(例如Plane和)实现RaceHorse

Horse 没有实现Flight。

如您所见,(抽象的或具体的)可帮助您构建层次结构,从而使您可以从层次结构的高层继承代码。从理论上讲,您在层次结构中的位置越低,您的行为就越专业,但是您不必担心许多已经处理的事情。

另一方面,接口不创建层次结构,但是它们可以帮助使某些行为在层次结构之间同质化,因此您可以在特定上下文中从层次结构中抽象出它们。

例如,您可以使一个程序将一组值相加,AccountableAssets而不管它们是RaceHorses还是Planes


惊人。接口提供了一定的功能部分,强加了can do/can be treated as抽象类作为基础的功能!
Abhiroj Panwar

13

您可以从逻辑上推断出答案,因为您似乎知道两者之间的差异。

接口定义公共合同。例如称为IAnimal的接口,其中所有动物共享诸如Eat(),Move(),Attack()等功能。尽管它们共享相同的功能,但所有或大多数动物具有不同的实现方式(实现)它。

抽象类定义了公共实现和可选的公共合同。例如,一个简单的计算器可以作为实现所有基本逻辑和按位运算符的抽象类,然后由ScientificCalculator,GraphicalCalculator等进行扩展。

如果您有通用的实现,那么一定要将功能封装在一个抽象类中,以从中扩展。我有将近0的PHP经验,但是我认为您不能使用非常量字段创建接口。如果这些字段在实例类之间是公用的,则除非您通过getter和setter定义对它们的访问,否则您将不得不使用Abstract类。

此外,Google似乎也不乏结果。


3

长话短说。抽象类与接口非常相似,它们都提供了继承类中应包含哪些方法的模板,但有很大的不同:-接口仅定义需要在继承类中存在的方法的名称/类型,而abs-类可以具有完整的方法默认代码,只是细节可能需要覆盖。-接口不能具有访问修饰符。-接口不能包含字段。-类不能具有多个类的继承,而它们可以继承多个接口。-而且,类提供了层次结构,因此只有从特定类派生的类才需要遵循抽象类的准则:对象->特定对象->非常特定的对象。另一方面,任何地方的任何人都可以继承接口。

在我看来,抽象类更为常见,因为它们可以立即提供默认的代码实现,但是在需要标准化某些类的大型项目中,接口可能会派上用场。

希望对您有所帮助,但Leo在此在线上有很多信息


2
Classes cannot have multiple inheritance-适用于Java和C#等语言,不适用于C ++。
罗伯特·哈维

3

首先,您应该了解您经常会同时提供接口和抽象类。这样做的原因以及两者之间的核心区别是,它们使您可以重用不同的代码,从而解决不同的问题。

接口允许您通过不同的实现重复使用客户端代码。您的get_data($ website)类的客户端不关心$ title或$ description项。它只想指示您的内容加载数据。如果您有不同类型的内容,其中一些需要$ description,而某些则不需要$ description,则可以提供ContentInterface类,该类仅指定子类的签名。现在,客户可以拥有任意数量的不同内容,而无需完全知道它们的工作方式。要研究此思想,可以阅读《里斯科夫替代原理》。我也喜欢鲍伯叔叔关于这个话题著作。接口对于单元测试非常重要,创建接口是一种学习的好习惯。

抽象类允许您在一组共享共同祖先的类之间重用共同的实现细节。在您的问题中,您似乎很好地理解了为什么要从抽象类继承实现。依靠基类的内部仍然很危险-违反封装并创建依赖于基类的特定实现细节的子代非常容易。该模板方法模式提供了如何使用基类不违反封装一个共同的和健康的例子。

因此,正如我希望的那样,您通常会为类层次结构的客户端提供接口,以便您可以安全地更改实现而不影响客户端代码。这允许客户端使用继承您接口的Mock对象编写单元测试。您还将提供抽象类,这些抽象类允许对子类重用公共逻辑或强制使用语义。


3

差异是微妙的,但很明显。接口是关于多态行为的。抽象类是关于重用和多态行为的。

如果要强调重用和多态行为,请选择抽象类。例如,不同类型的员工有不同的规定,但所有人都有一些共同点。这样,抽象类是合适的表示,因为共性可以在碱抽象类来表达Employee与差可以在派生类等来实现ManagerWorker

如果您只想强调多态行为,请选择接口。接口更多是关于契约的,即一个对象或层次结构说它符合某些行为。例如,所有雇员都有休假规定,但是不同类型的雇员有不同类型的规定。因此,每种不同类型的员工都需要不同的休假计算器。这里的界面是一个不错的选择,因为所有类型的员工都可以LeaveCalculatorCalculate()不同的方式实现界面。


-3
  1. 主要区别在于Java接口的方法是隐式抽象的,无法实现。Java抽象类可以具有实现默认行为的实例方法。
  2. 在Java接口中声明的变量默认为final。抽象类可能包含非最终变量。
  3. 默认情况下,Java接口的成员是公共的。Java抽象类可以具有类成员的常用风格,例如private,protected等。
  4. Java接口应使用关键字“ implements”来实现;Java抽象类应使用关键字“ extends”进行扩展。
  5. 一个接口可以扩展另一个Java接口,只有抽象类可以扩展另一个Java类并实现多个Java接口。
  6. Java类可以实现多个接口,但只能扩展一个抽象类。
  7. 接口绝对是抽象的,不能实例化;Java抽象类也无法实例化,但是如果存在main()则可以调用它。
  8. 与Java抽象类相比,Java接口速度较慢,因为它需要额外的间接调用。
  9. Java中的接口和抽象类是您不能在接口中创建非抽象方法,默认情况下,接口中的每个方法都是抽象的,但您可以在抽象类中创建非抽象方法。
  10. Java中的抽象类与接口的区别在于,接口更适合于类型声明,而抽象类则更适合于代码重用和演进观点。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.