.Net提供了接口,这个不同于Class或者Struct的类型定义。接口有些情况,看似和抽象类一样,因此有些人认为在.Net可以完全用接口来替换抽象类。其实不然,接口和抽象类各有长处和缺陷,因此往往在应用当中,两者要结合来使用,从而互补长短。

接下来先说说抽象类和接口的区别。

区别一,两者表达的概念不一样。抽象类是一类事物的高度聚合,那么对于继承抽象类的子类来说,对于抽象类来说,属于“是”的关系;而接口是定义行为规范,因此对于实现接口的子类来说,相对于接口来说,是“行为需要按照接口来完成”。这些听起来有些虚,举个例子。例如,狗是对于所有狗类动物的统称,京哈是狗,牧羊犬是狗,那么狗的一般特性,都会在京哈,牧羊犬中找到,那么狗相对于京哈和牧羊犬来说,就属于这类事物的抽象类型;而对于“叫”这个动作来说,狗可以叫,鸟也可以叫。很明显,前者相当于所说的是抽象类,而后者指的就是接口。

区别二,抽象类在定义类型方法的时候,可以给出方法的实现部分,也可以不给出;而对于接口来说,其中所定义的方法都不能给出实现部分。

例如:

public abstract class AbsTest

{

public virtual void Test()

{

Debug.WriteLine( "Test" );

}

public abstract void NewTest();

}

public interface ITest

{

void Test();

void NewTest();

}

区别三,继承类对于两者所涉及方法的实现是不同的。继承类对于抽象类所定义的抽象方法,可以不用重写,也就是说,可以延用抽象类的方法;而对于接口类所定义的方法或者属性来说,在继承类中必须要给出相应的方法和属性实现。

区别四,在抽象类中,新增一个方法的话,继承类中可以不用作任何处理;而对于接口来说,则需要修改继承类,提供新定义的方法。

知道了两者的区别,再来说说,接口相对于抽象类的优势。

好处一,接口不光可以作用于引用类型,也可以作用于值类型。而抽象类来说,只能作用于引用类型。

好处二,.Net的类型继承只能是单继承的,也就是说一个类型只能继承一个类型,而可以继承多个接口。其实,我对于这一点也比较赞同,多继承会使继承树变的混乱。

好处三,由于接口只是定义属性和方法,而与真正实现的类型没有太大的关系,因此接口可以被多个类型重用。相对于此,抽象类与继承类的关系更紧密些。

好处四,通过接口,可以减少类型暴露的属性和方法,从而便于保护类型对象。当一个实现接口的类型,可能包含其他方法或者属性,但是方法返回的时候,可以返回接口对象,这样调用端,只能通过接口提供的方法或者属性,访问对象的相关元素,这样可以有效保护对象的其他元素。

好处五,减少值类型的拆箱操作。对于Struct定义的值类型数据,当存放集合当中,每当取出来,都需要进行拆箱操作,这时采用Struct+Interface结合的方法,从而降低拆箱操作。

相对于抽象类来说,接口有这么多好处,但是接口有一个致命的弱点,就是接口所定义的方法和属性只能相对于继承它的类型(除非在继承类中修改借口定义的函数标示),那么对于多层继承关系的时候,光用接口就很难实现。因为如果让每个类型都去继承接口而进行实现的话,首先不说编写代码比较繁琐,有时候执行的结果还是错误,尤其当子类型对象隐式转换成基类对象进行访问的时候。

那么这时候,需要用接口结合虚方法来实现。

其实在继承中,到底使用接口还是抽象类。接口是固定的,约定俗成的,因此在继承类中必须提供接口相应的方法和属性的实现。而对于抽象类来说,抽象类的定义方法的实现,贯穿整个继承树,因此其中方法的实现或者重写都是不确定的。因此相对而言,抽象类比接口更灵活一些。

如下给出两者的简单对比表格。

接口

抽象类

多继承

支持

不支持

类型限制

没有

有,只能是引用类型

方法实现

继承类型中必须给出方法实现

继承类中可以不给出

扩展性

比较麻烦

相对比较灵活

多层继承

比较麻烦,需要借助虚函数

比较灵活

总的来说,接口和抽象类是.Net为了更好的实现类型之间继承关系而提供的语言手段,而且两者有些相辅相成的关系。因此我并不强调用什么而不用什么,那么问题的关键在于,如何把这两种手段合理的应用到程序当中,这才是至关重要。

什么是抽象类型?

抽象类是一种特殊的类,该类不能被实例化。抽象类的存在就是为了被继承,即抽象类可以被其它类继承但不能被实例化。那么,我们为什么需要一个无法被实例化的类呢?这样做的优点是,通过抽象类我们制定了一份强制所有子类必须遵守的合约,使所有子类有着一致的层次结构。抽象类提供了一种规范用于规定子类如何进行工作,子类可根据自身情况来重写抽象类中的抽象成员(及其它可被重写的成员)以满足自身需求。

抽象类作为一个基类,可以包含已实现的成员,同时应至少包含一个抽象成员,否则就没必要使用抽象类了。如果一个抽象类中仅仅包含抽象方法,那么这时抽象类就和接口很像了。

什么是接口?

接口中不能包含任何被实现的成员,即接口中只能包含成员的签名。如,没有方法体的方法、只包含访问器关键字(set、get)的属性等。和抽象类类似,接口也是一份合约。C#中,接口和抽象类的主要区别是,类可以实现多个接口,但只能继承一个(抽象)类。

比较异同

特征 接口 抽象类
是否支持多继承 支持 不支持
默认实现 接口中不能包含任何已实现的成员 抽象类中可以包含已实现(非抽象)的成员
访问修饰符 接口成员默认是公共(public)的,不再允许被任何访问修饰符修饰 抽象类成员可以被访问修饰符(不能是private)修饰
核心 VS 辅助 接口多用于定义(辅助性的)能力 抽象类多用于定义相同类型(这里类型不是数据类型的意思,解释见下文)子类所共有的一些特征
  若只提供一些方法上的约束,建议使用接口 如果子类属于同一类型,且具有相同的行为或状态,建议使用抽象类提供约束
寻找成员速度 相比抽象类较慢 相比接口更快
成员变动的影响 如果接口成员发生改动,则所有实现类都要进行改动 若向抽象类中添加非抽象成员,我们可以给该成员提供默认实现,这样子类就无需发生变动
允许包含的抽象成员 属性、方法、事件、索引器(这四类本质上都是方法) 属性、方法、事件、索引器
是否允许定义字段 不允许 不允许定义使用abstract修饰的字段

抽象类是对子类的抽象,即将子类中的公共部分提取出来,放到一个特定的类中。抽象类是一份合约,用于为同一类型(这里类型不是指数据类型,而是逻辑上的划分,如人和猫都是动物)的子类提供约束。
接口也是一份合约,但接口多用对能力的定义,即用于指定实现类能做哪些事儿。

例如:

人和猫,都属于动物这个大类,我们可以抽象出二者的公共部分。如,年龄、体重、吃、会叫(用于形容人不太友好)等作为一个抽象类的成员。

此外,人和猫相比,人会制作工具而猫不行,那么制作工具的技能就是人所特有的,这时可以定义一个接口提供对制作工具这项技能的约束

再如,人、车、猫三者都可以跑,那么也可以定义个接口用于对跑这项技能提供约束。

  • 抽象类和接口都是一种约束,这种约束使我们的代码有更好的层次结构,特别是在多人协同开发时(若每个人都按照自己的习惯来,对整个开发团队而言,开发成本不知要提高多少)。

  • 抽象类是对相同类型(不是数据类型)子类公共部分的抽象(约束),接口是对能力的一种约束。

C#_接口与抽象类的更多相关文章

  1. Java千百问_05面向对象(005)_接口和抽象类有什么差别

    点击进入_很多其它_Java千百问 1.接口和抽象类有什么差别 在Java语言中.抽象类abstract class和接口interface是抽象定义的两种机制. 正是因为这两种机制的存在,才赋予了J ...

  2. java_基础_接口和抽象类

    1.接口 java中接口的存在意义是:让多个继承该接口的类实现多态,让多个类有相同的特征 示例代码: interface MyInterface{ void myMethod(); } class T ...

  3. java-继承进阶_抽象类_接口

    概要图 一, 继承的进阶 1.1,成员变量 重点明确原理. 特殊情况: 子父类中定义了一模一样的成员变量. 都存在于子类对象中. 如何在子类中直接访问同名的父类中的变量呢? 通过关键字 super来完 ...

  4. luogg_java学习_07_抽象类_接口_多态学习总结

    这篇博客总结了半天,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 , 抽象 一种专门用来做父类,被继承的. (模板) 格式: abs ...

  5. 接口和抽象类:Interface、abstract _【转】

    一.接口 接口是C#中很常见的工具,概念什么的就不说了,这里讲几个值得注意的小地方: 1.接口内部只能有函数.属性和事件的声明: interface IParent { void Show(); st ...

  6. 深入理解Java的接口和抽象类 _摘抄

    http://www.cnblogs.com/dolphin0520/p/3811437.html 原文 深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可 ...

  7. 第一节:从面向对象思想(oo)开发、接口、抽象类以及二者比较

    一. 面向对象思想 1. 面向过程(OP)和面向对象(OO)的区别: (1):面向过程就是排着用最简单的代码一步一步写下去,没有封装,当业务复杂的时候,改动就很麻烦了 (2):面向对象将复杂的业务分离 ...

  8. 从接口、抽象类到工厂模式再到JVM来总结一些问题

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习! 涉及到的知识点总结如下: 为什么使用接口? 接口和抽象类的区别 简单工厂模式总结 Java中new和newInstance的区别 J ...

  9. (转)深入理解Java的接口和抽象类

    原文地址: http://www.cnblogs.com/dolphin0520/p/3811437.html 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP ...

随机推荐

  1. HDFS NameNode内存全景

    一.概述 从整个HDFS系统架构上看,NameNode是其中最重要.最复杂也是最容易出现问题的地方,而且一旦NameNode出现故障,整个Hadoop集群就将处于不可服务的状态,同时随着数据规模和集群 ...

  2. September 30th 2017 Week 39th Saturday

    The simplest answer is often the correct one. 最简单的答案通常是最正确的答案. Simplest is always best. Sometimes yo ...

  3. 51nod 1443 路径和树(最短路)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1443 1443 路径和树 题目来源: CodeForces ...

  4. 【转】彻底理解android中的内部存储与外部存储

    我们先来考虑这样一个问题: 打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据,那么当我们点击清除缓存的时候清除的是哪里的数据?当我们点击清除数据的 ...

  5. Linux MySql5.6.38安装过程

    1.下载mysql安装包mysql-5.6.38-linux-glibc2.12-x86_64.tar.gz 2.用xftp工具将其上传到Linux服务器上的soft文件夹,没有的话先创建 [root ...

  6. npm发布插件步骤

    开发好一个插件后,要想让其他人也能使用该插件需要将插件发布到npm上,具体步骤如下: 1.添加npm用户: npm adduser Username: your name Password: your ...

  7. IPython学习笔记(二)-魔术命令

    .魔术命令:以%为前缀的命令,是ipython的特殊命令,方便完成常见的任务.,常见的魔术命令有:%run,%paste,%cpaste,%timeit,%reset,%hist,%debug,%bo ...

  8. Python高级编程和异步IO并发编程

    第1章 课程简介介绍如何配置系统的开发环境以及如何加入github私人仓库获取最新源码. 1-1 导学 试看 1-2 开发环境配置 1-3 资源获取方式第2章 python中一切皆对象本章节首先对比静 ...

  9. vmvare安装系统提示vmci.sys 版本不正确解决方法

    无法获取vmci驱动程序版本:参数不正确解决 无法获取vmci驱动程序版本:参数不正确. 驱动程序vmci.sys版本不正确. 解决办法: 1,创建好虚拟机之后,别打开电源,然后到建好的虚拟机文件夹里 ...

  10. jenkins slave 挂载

    http://blog.sina.com.cn/s/blog_13cc013b50102wiau.html