抽象类与接口的区别

    • 语法定义层面
  • abastract class

  1. abstract class Demo{
  2. abstract void method1();
  3. abstract void method2();
  4. ...
  5. }
  • interface
  1. interface Demo{
  2. void method1();
  3. void method2();
  4. }
  • 使用abstract class方式定义Door:
  1. abstract class Door{
  2. abstract void open();
  3. abstract void close();
  4. }
  • 使用interface方式定义Door:
  1. interface Door{
  2. void open();
  3. void close();
  4. }
  • 其它具体的Door类型可以extends使用abastract class方式定义的Door或者implements使用interface方式定义的Door,看起来好像使用abstract class和interface没有大的区别。

  • 如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢有以下几种解决方案。

  • 解决方案1

    • 简单的在Door的定义中增加一个alarm方法,如下:
  1. abstract class Door{
  2. abstract void open();
  3. abstract void close();
  4. abstract void alarm();
  5. }
  1. interface Door{
  2. void open();
  3. void close();
  4. void alarm();
  5. }
  • 那么具有报警功能的AlarmDoor的定义方式如下:
  1. class AlamDoor extents Door{
  2. void open(){...}
  3. void close(){...}
  4. void alarm(){...}
  5. }
  1. class AlarmDoor implements Door {
  2. void open(){...}
  3. void close(){...}
  4. void alarm(){...}
  5. }
  • 这种方法违反了面向对象设计中的一个核心原则ISP(interface Segregation Principle),在Door的定义中把Door概念本身固有的行为方法和另外一个概念“报警器“的行为混在了一起。这样引起的问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变。

  • 解决方案二:

    • 既然open、close和alarm属于不同的概念,根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中,定义方式有:这两个概念都使用abstract class定义;这两个概念都使用interface来定义,一个概念使用abastract class 方式定义,另一个概念使用interface方式定义。

    • 显然,由于java语言不支持多生继承,所以两个概念都使用abstract class 方式定义是不可行的,后面两种方式都是可行的。但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图反映是不否正确、合理。

    • 如果两个两个概念都使用interface方式来定义,那么反映出两个问题:1、我们可能没有理解清楚问题领域,AlarmDoor在概念本质上到底是Door还是报警器?2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一对致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这个两个概念的定义上,反映不出上述含义。

    • 如果我们对于问题领域的理解是:AlarmDoor在概念本质上是Door,同时它有具有报 警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经说过,abstract class在Java语言中表示一种继承关系,而继承关系 在本质上是"is-a"关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说 明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示:

  1. abstract class Door{
  2. abstract void open();
  3. abstract void close();
  4. }
  5. interface Alarm{
  6. void alarm();
  7. }
  8. class Alarm Door extends Door implements Alarm
  9. {
  10. void open(){…}
  11. void close(){…}
  12. void alarm(){…}
  13. }
  • 这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其 实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。

  • 小结

    • abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系(无多重继承)。但是,一个类却可以实现多个interface。
    • 在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
    • abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。
    • 实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
    • 接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
    • 抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
    • 接口中的方法默认都是 public,abstract 类型的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值