C#中的抽象类abstract与开闭原则

什么是接口和抽象类:

具体类→抽象类→接口:越来越抽象,内部实现的东西越来越少

抽象类是未完全实现逻辑的类(可以有字段和非public成员,它们代表了“具体逻辑”)

抽象类为复用而生:专门作为基类来使用,也具有解耦功能

封装确定的,开放不确定的,推迟到合适的子类中去实现

接口是完全未实现逻辑的“类”(“纯虚类”;只有函数成员;成员全部public)

接口为解耦而生:“高内聚,低耦合”

都不能实例化,只能用来声明变量、引用具体类(concrete class)的实例

抽象类abstract

在介绍抽象类前,先介绍一个设计原则,SOLID设计原则中的Open Close Principle(开闭原则),抽象类和开闭原则之间有非常密切的联系,SOLID设计原则介绍:https://www.cnblogs.com/huangenai/p/6219475.html,开闭原则(OCP)认为“软件体应该是对于扩展开放的,但是对于修改封闭的”的概念,意思就是说我们应该封装不变的、稳定的、确定的成员,而把不确定、有可能改变的成员声明为抽象成员,并留给子类去实现。下面使用代码实例来介绍抽象类:

首先定义两个类Car(汽车类)和Truck(卡车类)

C#中的抽象类abstract与开闭原则

两个类都有Run(跑)、Stop(停)两个方法,我们发现两个类具有相同方法Stop(),这个时候我们可以定义一个基类(Vehicle)来实现这个相同方法,然后使两个类都派生至基类(Vehicle)。

C#中的抽象类abstract与开闭原则

这时如果我们想实现多态,实例化基类调用Run()方法是不行的,因为基类里面没有实现Run()方法,只能调用基类成员。

C#中的抽象类abstract与开闭原则

这时一般的解决方法是在基类中再加入一个Run()方法,传入参数,基类通过判断参数来实现Run()方法

C#中的抽象类abstract与开闭原则

但是如果我这时又添加了一个新的类(Racecar)来继承基类Vehicle,那么就又要修改基类Vehicle的代码,但是这样就严重的违反了开闭原则,除非修改或添加功能,否则我们不应该经常修改封装的基类代码,这样不易于后期维护。

C#中的抽象类abstract与开闭原则

解决这个问题,我们可以用virtual虚方法来实现,将基类中的Run()方法定义为虚方法,然后在子类中重写,那么在添加基类Vehicle的派生类时就不用修改基类的代码了。

C#中的抽象类abstract与开闭原则

但是我们发现基类Vehicel本身的Run()方法永远也不会执行,都是子类来重写它,那么它方法体里面的代码就没有意义,这时我们就可以把Run()方法定义成一个抽象方法,那么含有抽象方法的Vehicle类就变成了一个抽象类。

C#中的抽象类abstract与开闭原则

抽象类是不能实例化的,因为它含有抽象方法,没有方法体,就算创建实例成功,如果调用到抽象方法,没有方法体的实现,那么程序就会崩溃。

C#中的抽象类abstract与开闭原则

这里我们可以体会到抽象类是专为基类而生的,它的作用就是以基类类型来声明变量,并且引用已经完全实现了它那些抽象成员的子类类型的实例。

C#中的抽象类abstract与开闭原则

如果一个类中的所有成员都是抽象的,那么这个类就是一个接口interface。

C#中的抽象类abstract与开闭原则

End!