博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【温故知新】c#抽象类abstract与接口interface
阅读量:6893 次
发布时间:2019-06-27

本文共 4558 字,大约阅读时间需要 15 分钟。

 1、什么是抽象类

先来看MSDN对抽象类描述:

抽象类是一些留有部分或全部成员未实现的类,以便可以由派生类来提供实现。

在面向对象的编程中,抽象类用作层次结构的基类,并表示不同对象类型组的通用功能。 正如名称“抽象”所暗指的,抽象类通常不会直接与问题域中的具体实体对应。 不过,抽象类会表示多个不同的具体实体之间的共同之处。

仅当存在已声明但未定义的抽象方法时,才会将类视为抽象类。 因此,具有抽象方法的类并不一定是抽象类。 除非类具有未定义的抽象方法,否则不要使用 AbstractClass 特性。

一个类只能从一个抽象(或任何其他类型)类继承。

那抽象又是什么呢?例如:汽车,卡车,电动车都可以抽象为车子,直升机,客机,战斗机,都可以抽象成飞机,而车子和飞机,都可以抽象成交通工具,逐步脱去“个性”,保留“共性”,这就是抽象,这也是面向对象多态继承的一部分。

当一个类抽象到其方法需要到子类中实现的时候,就应该使用抽象类而不是派生类。例如:直升机和客机,都能飞,但是在继承之前,你不知道飞机到底使用螺旋桨飞,还是用涡扇发动机飞,所以只能抽象成抽象类。

2、什么是接口

先来看MSDN的描述:

接口包含 类 或 结构 可以实现相关一组功能的定义。

由于C#语言不支持多重继承,但是可以实现多个借口,所以该功能很重要。

接口不能包含常数、字段、运算符、实例构造函数、析构函数或类型。 接口成员将自动是公共的,因此,它们不会包含任何访问修饰符。 成员也不能是 静态。

若要实现接口成员,实现的选件类的相应成员必须是公共的,非静态的,并且具有名称和签名和接口成员相同。

小时候玩过拼图,每个小图片通过卡扣一个个连接起来成为一幅图,这个小卡扣就是非常形象的“接口”,一个庞大的系统,也是通过每个模块的接口拼接起来的。

可以这么理解,一个接口就是一个类实现外界公布的方法约定,使我们知道这个类肯定有这么一个方法来实现我们的需求

例如:我们都知道汽车有“油门”,我们不用管这个车子是电动还是汽油还是柴油,不管用的什么高级还是低级发动机,只要轻轻踩一脚,车子就可以动起来,对外界来说,“油门”就相当于一个接口,汽车实现了这个接口,我们就知道可以通过踩油门来启动汽车。那如果哪天自行车也实现了“油门”,我们也不管那么多这自行车内部到底是怎么实现的(我不想知道也不用知道,对于消费者来说,和我无关),反正踩自行车的油门,自行车肯定就会自己动起来了。

所以接口是具有普遍“共性”的方法约定。

3、什么时候使用抽象类,接口?

直接看一段以“硬盘”为抽象的代码场景演示:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace AbstractAndInterface{    ///     /// 通用USB接口,插到电脑上,电脑只认这个方法,来读取插入东西的数据,对于其他东西都不管    ///     public interface USB_Interface    {        string USBReadData();    }    ///     /// 通用蓝牙接口,开启蓝牙之后,电脑只认这个方法,来读取插入东西的数据,对于其他东西都不管    ///     public interface BlueTooth_Interface    {        string BlueToothReadData();    }    ///     /// 硬盘抽象类    ///     public abstract class Disk    {        //抽象方法读数据,因为子类读取方法不能确定(HDD磁盘寻道,SSD闪存颗粒直接读),所以声明抽象函数,那么这个类肯定就要声明为抽象类。        public abstract string ReadData();    }    ///     /// 实现了通过USB和蓝牙传输数据的接口    ///     public class SSD_Disk : Disk, USB_Interface, BlueTooth_Interface    {        public override string ReadData()        {            return "SSD通过闪存颗粒超高速读数据!";        }        public string USBReadData()        {            return "通过USB数据传输:" + ReadData();        }        public string BlueToothReadData()        {            return "通过BlueTooth数据传输:" + ReadData();        }    }    ///     /// 实现了通过USB和蓝牙传输数据的接口    ///     public class HDD_Disk : Disk, USB_Interface, BlueTooth_Interface    {        public override string ReadData()        {            return "HDD通过磁性碟片读数据!";        }        public string USBReadData()        {            return "通过USB数据传输:" + ReadData();        }        public string BlueToothReadData()        {            return "通过BlueTooth数据传输:" + ReadData();        }    }    public class Computer    {        ///         /// 电脑只管通过接口来读取数据,不管你是什么设备,反正返回给我数据就行。        ///         ///  实现usb接口的设备        /// 
public string ReadUSB(USB_Interface usbDevice) { return usbDevice.USBReadData(); } } class Program { static void Main(string[] args) { USB_Interface ssd = new SSD_Disk(); USB_Interface hdd = new HDD_Disk(); Computer computer = new Computer(); Console.WriteLine(computer.ReadUSB(ssd)); Console.WriteLine(computer.ReadUSB(hdd)); } }}

对以上代码,我的总结如下:

1、Computer类通过USB_Interface来读取设备数据,这样这个USB设备对于Computer类来说是透明的(Disk没有曝光),Computer也不需要知道具体的类,只知道调用这个接口,你返回给我数据就行,提高内聚,低耦合,否则,如果有新的不是继承自Disk类的存储设备,Computer类岂不是要新写一个方法读取数据?

2、通过接口,我们能够很方便的对类进行功能扩展以及功能组合。否则使用抽象类,多一个功能就要继承一次,代码工作量非常大,子类划分也非常不明显

例如:

///     /// 硬盘抽象类    ///     public abstract class Disk    {        //抽象方法读数据,因为子类读取方法不能确定(HDD磁盘寻道,SSD闪存颗粒直接读),所以声明抽象函数,那么这个类肯定就要声明为抽象类。        public abstract string ReadData();    }    public abstract class UsbDisk : Disk    {        public abstract string USBReadData();    }    public abstract class BlueToothDisk : Disk    {        public abstract string BlueToothReadData();    }    public abstract class BlueToothAndUsbDisk : Disk    {        public abstract string USBReadData();        public abstract string BlueToothReadData();    }

3个不同功能的Disk产品的继承(类只能单继承),这还没有具体实现就已经感觉很复杂了,那如果要分别实现SSD和HDD,就更加复杂了。

在设计之初就应该发现,USB与BlueTooth其实和Disk没有太大的关联(是普遍产品具有的“共性”方法约定),它是一种外部数据通讯方式,应该提取为接口。但如果是Disk内部某两个部件之间的数据流通方法(子类实现方式不同),则可以定义为抽象函数。

3、面向接口编程,如果哪天蹦出一个新的存储设备,电脑不用做任何改变(新设备原理什么的我都不管,反正我调用接口,你就要返回给我数据),也可以直接读取新设备的数据(实际上USB通用接口的原理也是这样)。

最后看看MSDN上的总结:

  • 如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单易行的方法来控制组件版本。通过更新基类,所有继承类都随更改自动更新。另一方面,接口一旦创建就不能更改。如果需要接口的新版本,必须创建一个全新的接口。
  • 如果创建的功能将在大范围的全异对象间使用,则使用接口。抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。
  • 如果要设计小而简练的功能块,则使用接口。如果要设计大的功能单元,则使用抽象类。
  • 如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。抽象类允许部分实现类,而接口不包含任何成员的实现。

转载于:https://www.cnblogs.com/leestar54/p/4593173.html

你可能感兴趣的文章
linux 切换用户之后变成-bash-3.2$的解决方法
查看>>
我的友情链接
查看>>
使用list
查看>>
Ubuntu 12.04 安装 gcc-4.8 及 gdb 7.6
查看>>
GII 和 DEBUG 模块出现 403 解决
查看>>
shell历史命令记录功能
查看>>
kali linux软件源
查看>>
cocos2d_x在windows环境下的方向键支持
查看>>
Maven学习总结(11)——Maven Tomcat7自动部署
查看>>
zabbix安装界面报连接不到数据
查看>>
pjsip 同时使用多套音频设备
查看>>
DevOps:怎么实现源代码注释和系统文档的自动化更新?
查看>>
make 中的路径搜索(十二)
查看>>
zabbix agent 端主动注册
查看>>
初识Mysql(二)
查看>>
监控系统的状态
查看>>
Samba文件共享服务
查看>>
软件目录开发规范
查看>>
compute post expression
查看>>
C#中DataTable中的Compute方法使用收集
查看>>