22

工作好多年有可能还未真正了解接口和抽象类

 3 years ago
source link: https://studygolang.com/articles/30611
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

UvAFJjM.png!mobile

  1. 抽象类和接口的定义和区别?
  2. 抽象类在面向对象编程中解决了什么问题?
  3. 接口在面向对象编程中解决了什么问题?
  4. 如何决定该用抽象类还是接口?
  5. 如果使用的语言不支持抽象类和接口,该如何应对?

抽象类

在面向对象编程的语言中,多数都添加了对抽象类和接口的支持,比如最常用的java,C#等语言。

//抽象类
    public abstract class Human
    {
        //抽象方法
        public abstract string Gender();
        //属性
        public string Name { get; set; }
        //方法
        public int GetAge()
        {
            return 1;
        }
    }

以上是一个普通的抽象类的定义,具体怎样使用,度娘有一大堆结果,其实总体来说抽象类主要有以下几点特征:

  1. 抽象类不能被实例化,只能被继承。也就是说如果 New Human()会报编译错误
  2. 抽象类也是类,可以包含属性和方法,方法可以包含实现,也可以不包含,不包含实现被称为抽象方法。
  3. 子类继承抽象类,必须要实现定义的所有抽象方法,不然编译器会报编译错误。

抽象类本质上还是类,只不过是一种不能被实例化的特殊类而已,但是在面向对象的设计过程中却起着非常重要的地位,本质上抽象类体现的是is-a的关系,就像上边定义的抽象类一样,Human类型抽象的是人类,假如我定义一个菜菜的类型来继承这个类型

public class CaiCai : Human
    {
        public override string Gender()
        {
            return "男";
        }

    }

CaiCai这个类必须要提供抽象方法的实现才可以通过编译。抽象类的产生是面向对象开发思想的延伸,是解决代码复用问题的一个方案,更是把代码进行抽象化的一个结果。抽象类的设计思想是自下而上的,也就是说设计上应该先有子类,当子类逐渐增加,进而抽象出共用特性而产生抽象类。

说到这里,好多同学会问,如果我不用抽象类做父类也可以啊。不错,普通的类当然也可以代替抽象类的地位。但是有几点就看起来比较奇怪了

  1. 父类也可以进行实例化了,但是其中要抽象的方法看起来就比较怪了,因为这些方法只有子类中才有明确的定义,比如 以上代码中Human这个类如果修改为普通类型,那方法Gender()该返回什么内容呢?
  2. 在编译期间,如果子类没有实现父类的方法是不会报错的,这就加大了排查问题的难度,如果需要重写的方法很多,之后排查问题会非常头疼
  3. 抽象出来的父类如果可以被实例化,这本质上违反了面向对象的思想,毕竟父类是一个抽象化的概念,被实例化之后代表着什么比较令人困惑

接口

接口在系统设计中,最重要的作用就是解耦。你应该听过不止一次的“面向接口编程”和依赖倒置等思想,这些也是面向对象设计思想的一种体现。接口本质上是抽象出来的对象的行为,或者叫做契约。在面向接口开发中,调用者不关心接口的实现,而是依赖于接口的定义,接口定义的稳定性代表着一个系统的稳定性,如果一个系统对外的接口定义有问题,那这个系统多半是会死人的。

public interface IHuman
    {
        //接口行为定义
        void Walk();
    }

以上只是一个简单接口的定义而已,接口的抽象小到可以是一个对象的行为抽象,大到可以是一个服务的行为抽象,更有可能是一个系统的行为抽象,所以接口是一个很泛的概念,但是本质上还是反应的是面向对象设计理念。由于接口是行为的定义,所以就决定了它有以下特点

  1. 接口只能定义行为,不能包含行为的实现
  2. 类型继承接口的时候,必须要实现接口的所有行为
  3. 接口不同于类,不能包含属性

由于接口体现的是行为准则,所以接口在定义的时候也可以利用面向对象设计理念,当多个不同接口定义了相同的行为,可以考虑抽象出更上层的接口来实现行为的复用。

写在最后

抽象类和接口都是对象的抽象行为产生的,只不过抽象类更加侧重于 is-a 的关系,它实现了代码复用,而接口更加侧重于行为的抽象(has -a),举一个很简单的栗子,如果设计一个鸟类的抽象该怎么做呢?不同的鸟可能羽毛的颜色不一样,像这样的属性可以利用抽象类,不同的鸟类可能会有不同的飞行行为,这样行为类的抽象利用接口来实现更加合适。

无论是接口还是抽象类,在代码层次上体现的是上下级关系,就算一个编程语言没有提供接口和抽象类的定义,只要能实现对象上下级关系,原理上也可以实现面向对象编程。编程的抽象思想始终在围绕着上下,内外这几个维度在合理的进化着。

说到接口的定义,其实还可以在泛化一下,接口中只有行为方法的定义,在一些不支持接口的编程语言中,可以把只包含方法的类看做接口的抽象定义,这在设计理念上是说的通的。

在继承层次上和设计流程上,抽象类是一种自下而上的设计思路,先有子类的代码,当子类逐渐增多,才会抽象出更加上层的父类。而接口不同,面向接口编程是一种自上而下的设计思路,先抽象出行为契约,然后才是实现。

更多精彩文章

mMBj6j7.png!mobile

有疑问加站长微信联系

iiUfA3j.png!mobile

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK