【问题标题】:Why use abstract class and not interface?为什么使用抽象类而不是接口?
【发布时间】:2012-08-20 14:26:52
【问题描述】:

例如,一位房地产建筑商正在建造一套带有许多公寓的公寓。除卧室外,公寓中的所有房间都具有相同的设计。卧室设计留给拥有公寓的人,即;床 房间可以针对不同的公寓进行不同的设计。

我可以通过如下abstract 类来实现这一点:

public abstract class Flat
{
    //some properties

    public void livingRoom(){
       //some code
    }

    public void kitchen(){
       //some code
    }

    public abstract void bedRoom();

    }
}

implementation 类如下:

public class Flat101 extends Flat
{
    public void bedRoom() {
        System.out.println("This flat has a customized bedroom");
   }        

}

或者,我可以使用interface 而不是abstract 类来实现相同的目的,如下所示:

class Flat
{
  public void livingRoom(){ 
       System.out.println("This flat has a living room");
  }

  public void kitchen(){
     System.out.println("This flat has a kitchen");
  } 
}

interface BedRoomInterface
{
  public abstract void bedRoom();
}

public class Flat101 extends Flat implements BedRoomInterface
{
   public void bedRoom() {
    System.out.println("This flat has a customized bedroom");
   }
}

现在的问题是:为此为什么要选择使用interface(或)我为什么要选择使用abstract 类?

【问题讨论】:

  • 你自己回答了:接口只定义方法名,如果你还需要实现某些方法,你使用抽象类。

标签: java oop interface abstract-class


【解决方案1】:

这取决于您的意图或用例。但总的来说,您应该更喜欢接口而不是抽象类(Bloch 的 Effective Java 中的第 18 条)。抽象类更脆弱,因为有人可能会修改抽象类,从而改变从它扩展的其他类的行为(这是一般性陈述)。

使用接口更灵活,因为如果你有 BedroomInterface 和 LivingRoomInterface,那么你可以让 FlatInterface 实现这两个接口,然后 Flat101 实现类实现 FlatInterface(而不是从 Flat 扩展然后实现一个接口)。这样看起来就更清楚了,以后你可以有ExecutiveFlatInterface,它不仅有卧室和客厅,还有猜测空间,然后Flat102就可以实现了。

选项 2 是让 Flat101 从 Flat 扩展,然后 Flat 实现 BedroomInterface 和 LivingRoomInterface。这实际上取决于您想要做什么以及可能需要什么方法。

【讨论】:

  • 我完全同意,但是现在既然可以使用默认操作在接口中指定实现,那么在接口上使用抽象类是一件好事吗?可能是你想限制子类不扩展其他类(无论出于何种原因)
  • @user8810865,抽象类支持包私有和受保护的字段、构造函数和继承类可以使用的方法。这些不能通过接口完成,因为默认操作必须是公共的。
【解决方案2】:

如果您要设计一个将被广泛使用的 API,您可以同时使用:一个接口来表达要通过实现类来实现的契约,以及一个抽象类,它部分实现该接口并因此允许代码重复使用。

以 Java 的 List 为例:Collections 框架中的方法(例如 Collections.sort())是根据 List 接口编写的,该接口部分由抽象类 AbstractList 实现,而抽象类又被扩展为具体实现 LinkedList 和 ArrayList。 LinkedList 和 ArrayList 重复使用 AbstractList 中的代码,但这并不妨碍人们编写自己完全独立的 List 实现,然后使用 Collections.sort() 对其进行排序。

也就是说,在很多情况下,这种方法可能有点矫枉过正。如果您正在构建的类型层次结构仅在相对较小的范围内使用,则通常只使用抽象类就可以了。如果您稍后决定以后需要一个接口,那么它是一项非常轻松的重构任务来改变事物。

抽象类确实有一些优点:

  • 它们允许您使用 package/protected 修饰符指定抽象方法
  • 它们有助于代码重用
  • 通过在超类上使用抽象方法和最终方法,它们允许您限制类的子类化方式,这在各种情况下都很有用(另请参见:模板模式)
  • 在 IDE 中引用类的代码通常更易于遵循(在抽象类类型参数上单击“打开声明”通常比在接口类型参数上更有用)

【讨论】:

    【解决方案3】:

    如果您有一个类提供派生类所需的某些功能,但每个派生类还需要其他功能的不同实现,那么抽象类提供了一种定义通用实现的方法,同时保留所需的特定行为由派生类具体到每个派生类。

    【讨论】:

      【解决方案4】:

      我觉得是泛化手段;如果类的属性和行为在给定的包或模块中是通用的,则抽象类是最有用的。一个很好的例子是鼓式制动器。由于所有鼓式制动器的工作方式都与在轮鼓内保持制动器的方式相同,因此这种行为可以在所有使用鼓式制动器的汽车中继承。

      对于接口;它更像是规范或合同,迫使您实施其物种形成。让我们以建筑物模型为例,它具有门、窗、电梯等所有形态……但是当您将模型实施到实际建筑物中时,我们需要保留窗户,但内部行为由(因为寡妇可以是一个简单的寡妇或滑块窗口,颜色和材质……)

      希望这会有所帮助!

      【讨论】:

        【解决方案5】:

        我觉得当我们需要为多个类实现一些通用功能和一些抽象功能时,我们应该使用抽象类。如果我们看到 Flat 的例子,我们有一些通用设计和一些自定义设计,在这种用例中最好使用抽象而不是再次使用接口来实现自定义功能,并且使用抽象作为派生类不会创建作为普通派生类的额外实例。

        【讨论】:

          【解决方案6】:

          您不能扩展多个类,但可以实现多个接口

          如果您需要经常更改设计,那么抽象类会更好,因为任何更改都发生在抽象类中,不需要在子类中强制实现。但是如果接口有任何变化,你必须实现实现类。

          【讨论】:

          • 不错@maba。我们需要引用我们的消息来源!
          • 感谢您编辑您的答案,而不是离开抄袭版本。我认为当您说“经常更改设计”时,您需要具体说明。此外,“子类中不需要强制实现”也可能很危险,因为可能有些类实际上需要覆盖它而不是采用默认实现,这就是我们使用“抽象”关键字来强制实现的原因。
          • 任何改变都意味着添加抽象方法
          猜你喜欢
          • 2013-09-21
          • 1970-01-01
          • 2020-07-06
          • 2012-04-24
          • 2014-07-23
          • 2011-01-10
          • 1970-01-01
          • 2017-03-14
          • 1970-01-01
          相关资源
          最近更新 更多