抽象与接口

接口与抽象很多方面相似,下面列出其共同点。

1.都不能创建实例对象,因为他们都是抽象的。

2.虽然不能直接通过关键字“new”创建实例对象,但可以声明变量,通过变量指向子类或实现类的对象,来创建实例对象。

两者也有不同点,如下所示。

1.Java不支持多重继承,即一个子类只能拥有一个父类,抽象类也是如此。但一个子类可以实现多个接口。

2.接口内不能有实例字段,只能有静态常量。抽象类可以有实例字段。

3.接口内的方法自动设置为“public”的。抽象类中的方法必须手动声明访问控制符。


抽象类和接口在概念上的区别

  声明方法而不去实现它的类被称作抽象类,它用于创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现这些方法的情况。不能创建abstract类的实例,但可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例,不能有抽象构造函数或抽象静态方法。abstract类的子类为其父类中的所有抽象方法提供实现,否则也是抽象类。

  接口是抽象类的变体,在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口只可定义“static final”成员变量,接口的实现与子类相似,但该实现类不能再接口定义中继承行为。

  当类实现特殊类接口时,需要实现这种接口的所有方法,然后,它可以在实现该接口的类的任何对象上调用接口的方法。抽象类允许使用接口作为引用变量的类型,引用可以转换到接口类型或从接口类型转换,“instanceof”运算符可决定某对象的类是否实现了接口。


从设计理念上看待抽象类和接口

   “abstract class”在Java语言中体现了一种继承关系。要想继承关系合理,父类和派生类之间必须存在“is a”关系,即父类和派生类在感念本质上应该是相同的。对于“interface”来说则不然,其并不要求“interface”实现者和“interface”定义在概念本质上是一致的,仅仅是实现了“interface”定义的契约而已。为了使论述便于理解,下面将通过一个简单的实例进行说明。

  考虑这样一个例子。假设有一个关于“door”的抽象概念,该“door”执行两个动作:“open”和“close”。此时可通过“abstract class”或者interface来定义一个表示该抽象概念的类型。定义方式分别如下所示:

  使用抽象类来定义door:

  abstract class door{
	  abstract void open();
	  abstract void close();
  }

  使用接口来定义door:

  interface door{
	  abstract void open();
	  abstract void close();
  }

  其他具体的“door”类型可以继承“abstract class”或者“interface”定义的“door”。看起来使用两者没什么大的区别,如果现在要求“door”还具有报警功能呢,该如何设计针对该例子的类结构呢?本例主要是为了展示“abstract class”和“interface”反映在设计理念上的区别,并从设计理念层次面对这些不同的方案进行分析。

  【解决方案一】

  简单的在“door”的定义增加一个“alarm”方法,如下所示:

  abstract class door{
	  abstract void open();
	  abstract void close();
     abstract void alarm();
   }
  或者:
       
  interface door{
	  abstract void open();
	  abstract void close();
        abstract void alarm();
   }

  那么具有报警功能的“alarmdoor”的定义方式如下:

  class alarmdoor extends door{
  	  void open(){..}
	  void close(){..}
	  void alarm(){..}
  }

  或者

  class alarmdoor implements door{
	  void open(){..}
	  void close(){..}
	  void alarm(){..}
  }

  这种方法违反了面向对象设计的一个核心原则ISP(interface segregation priciple)。在“door”的定义中,把“door”概念本身固有的行为方法和另一个概念“报警器”的行为方法混合在了一起。如果是这样,那些仅仅依赖于“door”概念的模块,会因为“报警器”这个概念的改变而改变,反之亦然。

  【解决方案二】

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

  显然,由于java不支持多重继承,所以方式一不可行。后面两个都可行,但是对他们的选择,应该反映出对于问题领域中的概念本质的理解,对于设计意图的反映是否正确、合理。下面一一来分析。

  如果两个概念都使用“interface”方式来定义,就反映出下面问题:

  □可能没有理解清楚问题领域,“alarmdoor”在概念本质上到底是“door”还是报警。

  □如果对于问题领域的理解没有问题,比如:通过对于问题领域的分析发现“alarmdoor”在概念本质上和“door”是一致的。那么,在实现时就没有能正确的揭示设计意图,因为在这两个概念的定义上(均使用interface定义)反映不出上述含义。

  □如果对于问题领域的理解是“alarmdoor”在概念本质上是“door”,同时它具有报警的功能。该如何明确的反映出上述意思呢?“abstract class”在java语言中表示一种继承关系,所以对于door这个概念,应该使用“abstract class”方式来定义。另外,“alarmdoor”又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警概念可以通过“interface”方式定义

  class door{
	  abstract void open();
	  abstract void close();
  }
  interface Alarm{
	  void alarm();
  }
  class alarmdoor extends door implements Alarm{
	  void open(){..}
	  void close(){..}
	  void alarm(){..}
  }
  如果认为“alarmdoor”在概念本质上是报警器,同时又具有“door”的功能,那么上述的定义方式就要反过来。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值