为什么使用抽象类而不是接口?

时间:2012-08-25 04:59:22

标签: java oop interface abstract-class

例如,房地产建造者正在建造一个有许多单位的公寓。除卧室外,公寓的所有客房均采用相同的设计。卧室的设计留给了拥有公寓的人,即;床的房间可以有不同的设计,适合不同的公寓。

我可以通过下面的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类?

6 个答案:

答案 0 :(得分:6)

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

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

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

答案 1 :(得分:3)

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

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

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

抽象类确实有一些优点:

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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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

用于界面;它更像是规范或合同,迫使你实施其物种形成。让我们举一个建筑物模型的例子,它有各种各样的物种,如门,窗,升......但是当你将模型实施到实际建筑物中时,我们需要保持窗口,但内部行为是由(因为寡妇可以)是一个简单的寡妇或滑块窗口,颜色和材料......)

希望这有帮助!!

答案 4 :(得分:0)

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

答案 5 :(得分:-3)

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

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