抽象基类和接口

C#中的抽象基类(Abstract Class)和接口(Interface)都实现了面向对象中的继承机制,它们通过定义抽象方法匀实现了对继承类的功能上的约束,那么在如何在恰当的场景选择恰当的继承机制是我们在设计中经常会遇到的问题,我们先来对比两者之间的区别与联系。

相同点

  • 都可以被继承。
  • 本身都不能被实例化

不同点

  • 抽象类是一个不完整的类,需要进一步细化;而接口只是一个行为上的规范。
  • 抽象基类不能实现多继承,而接口可以实现多继承。
  • 抽象基类可以定义字段、属性、包含有实现的方法。接口可以定义字段、索引器、事件但不能定义字段和包含实现的方法。  

共性、个性与选择

有的书上写到C#中推荐使用接口(Interface)来替代抽象基类(Abstract Class),并强调使用接口的诸多好处,这点我不敢苟同,从上面列表中看来,两者之间还是存在不少差异的,而这种差异的存在性必然决定了适用场景的不同,例如在抽象基类中可以为部分方法提供默认的实现,从而避免在子类中重复实现它们,提高代码的可重用性,这是抽象类的优势所在;而接口中只能包含抽象方法。至于何时使用抽象基类何时使用接口关键还是取决于用户是如何看待继承类之间的联系的,用户更加关心的是它们之间的个性差异还是它们之间的共性联系。举个生活中的例子加以说明。

如果给你三个对象分别是人、鱼、青蛙,让你为他们设计个基类来概括它们之间的联系,那么首先给你的感觉肯定是它们个体间的差异性较大,很难抽象出共性,然而若让你概括他们行为之间的共性,你可能想了想会意识到他们都会游泳,只不过是游泳方式迥异。那么这时你就应当考虑使用接口而不是抽象基类,原因有三条:

  1. 个性大于共性。
  2. 差异较大的个性间具有某些相同的行为。
  3. 相同行为的实现方式有较大区别。

设计为: 好,这时再给你三个对象,分别是鲫鱼、鲤鱼、金鱼,仍然让你设计基类来概括它们之间的联系,那么你第一个意识到的肯定是它们都属于鱼类,其次是他们游泳的方式可能稍有差异,这时就应当使用抽象基类而不是接口,对比着上面的例子,原因也有三条:

 1       interface  ISwim  2      {  3           void  Swim();  4      }  5   6       public   class  Person : ISwim  7      {  8           public   void  Swim()  9          { 10               // Swimming in person's style. 11          } 12      } 13  14       public   class  Frog : ISwim 15      { 16           public   void  Swim() 17          { 18               // Swimming in frog's style. 19          } 20      } 21  22       public   class  Fish : ISwim 23      { 24           public   void  Swim() 25          { 26               // Swimming in fish's style. 27          } 28      }

 

  1. 共性大于个性
  2. 共性相同的个体间必然具有相同的属性与行为。
  3. 相同行为的实现方式具有一定区别。

设计为: 总结:

 1       abstract   public   class  Fish  2      {  3           abstract   public   void  Swim();  4      }  5   6       public   class  鲫鱼 : Fish  7      {  8           public   override   void  Swim()  9          { 10               // Swim like a 鲫鱼 11          } 12      } 13  14       public   class  鲤鱼 : Fish 15      { 16           public   override   void  Swim() 17          { 18               // Swim like a 鲤鱼 19          } 20      } 21  22       public   class  金鱼 : Fish 23      { 24           public   override   void  Swim() 25          { 26               // Swim like a 金鱼 27          } 28      }

 

观察在使用接口或是使用抽象基类的几条理由中,第三条理由其实是一样的,它所描述的是面向对象中多态的概念,即通过覆盖父类的方法来实现,在运行时根据传递的对象引用,来调用相应的方法。第二条理由开始产生分歧,接口更加强调了继承对象间具有相同的行为,而抽象类同时还强调了继承对象间具有相同的属性。而真正将接口与抽象基类区分开的则是理由一,归纳如下:

  1. 当在差异较大的对象间寻求功能上的共性时,使用接口。
  2. 当在共性较多的对象间寻求功能上的差异时,使用抽象基类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值