抽象类 VS 接口

引言

接口和抽象类是面向对象编程(OOP, Object Oriented programming)中两个绕不开的概念,二者相似而又有所不同。接下来,我们来了解二者的概念并比较它们的异同。

什么是抽象类型?

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

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

什么是接口?

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

比较异同

特征

接口

抽象类

是否支持多继承

支持

不支持

默认实现

接口中不能包含任何已实现的成员

抽象类中可以包含已实现(非抽象)的成员

访问修饰符

接口成员默认是公共(public)的,不再允许被任何访问修饰符修饰

抽象类成员可以被访问修饰符(不能是private)修饰

核心 VS 辅助

接口多用于定义(辅助性的)能力

抽象类多用于定义相同类型(这里类型不是数据类型的意思,解释见下文)子类所共有的一些特征

若只提供一些方法上的约束,建议使用接口

如果子类属于同一类型,且具有相同的行为或状态,建议使用抽象类提供约束

寻找成员速度

相比抽象类较慢

相比接口更快

成员变动的影响

如果接口成员发生改动,则所有实现类都要进行改动

若向抽象类中添加非抽象成员,我们可以给该成员提供默认实现,这样子类就无需发生变动

允许包含的抽象成员

属性、方法、事件、索引器(这四类本质上都是方法)

属性、方法、事件、索引器

是否允许定义字段

不允许

不允许定义使用abstract修饰的字段

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

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

abstract class Animal
{
    public abstract int Age { set; get; }
    public abstract float Weight { set; get; }
    public abstract void Call();
    //默认实现
    public virtual void Eat()
    {
        Console.WriteLine("猫粮......");
    }
}


class Person : Animal
{
    public override int Age { set; get; }
    public override float Weight { set; get; }

    public override void Eat()
    {
        Console.WriteLine("鱼香肉丝盖饭......");
    }

    public override void Call()
    {
        Console.WriteLine("雷好啊......");
    }
}

class Cat : Animal
{
    public override int Age { set; get; }
    public override float Weight { set; get; }

    public override void Call()
    {
        Console.WriteLine("喵喵喵......");
    }
}

那么,只要继承Animal类的类都应属于动物这个大类,汽车就不应该继承Animal类。 此外,人和猫相比,人会制作工具而猫不行,那么制作工具的技能就是人所特有的,这时可以定义一个接口提供对制作工具这项技能的约束,然后让Person类实现该接口。

interface ICreatTool
{
    void CreateTool();
}

class Person : Animal, ICreatTool
{
    public override int Age { set; get; }
    public override float Weight { set; get; }

    public override void Eat()
    {
        Console.WriteLine("鱼香肉丝盖饭......");
    }

    public override void Call()
    {
        Console.WriteLine("雷好啊......");
    }

    public void CreateTool()
    {
        Console.WriteLine("造台MAC......");
    }
}

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

interface IRun
{
    void Run();
}

class Person : IRun
{
    public void Run()
    {
        Console.WriteLine("11路公交......");
    }
}

class Cat : IRun
{
    public void Run()
    {
        Console.WriteLine("四蹄奔腾......");
    }
}

class Car : IRun
{
    public void Run()
    {
        Console.WriteLine("四轮......");
    }
}

小结

用简单的话概括接口和抽象类的异同:

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

此外,建议大家读一读文末给出的这篇文章,本人读完收益颇多,本文中的表格部分引自该文。

参考文章

Abstract Class versus Interface

版权声明

本文为作者原创,版权归作者雪飞鸿所有。 转载必须保留文章的完整性,且在页面明显位置处标明原文链接

如有问题, 请发送邮件和作者联系。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏xingoo, 一个梦想做发明家的程序员

《JavaScript语言精粹》—— 读书总结

话说这本书还是同学的推荐才读的,之前感觉这本书太薄了,不值得看,没想到小身材有大智慧,书中的内容总结的还是很到位的!所以就把最后几章,精华的部分整理整理。 优...

28190
来自专栏C/C++基础

STL四种智能指针

STL一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr和weak_ptr,auto_ptr是C++98提供的解决方案,...

42930
来自专栏数据结构与算法

1487 大批整数排序

个人博客:doubleq.win 1487 大批整数排序  时间限制: 3 s  空间限制: 16000 KB  题目等级 : 黄金 Gold 题解 题目描述 ...

30260
来自专栏Flutter入门

有趣的正则表达式

听到正则表达式,大家一定不会陌生。工作项目中也经常使用正则表达式来校验文本的是否匹配规则。通常都会直接上网找寻各种格式输入的正则匹配式。比如电话/邮件等等。

12530
来自专栏大内老A

深入理解C#3.x的新特性(4):Automatically Implemented Property

深入理解C#3.x的新特性系列在沉寂一个月之后,今天继续。在本系列前3部分中,我们分别讨论了Anonymous Type,Extension Method和La...

20270
来自专栏程序员互动联盟

【专业技术】STL hash_map使用(一)

今天在使用STL中的hash_map模板遇到使用PTCHAR作为Key时无法对字符串进行正确比较的问题。 hash_map类在头文件hash_map中,和所有其...

33280
来自专栏大内老A

深入理解C# 3.x的新特性(2):Extension Method[上篇]

在C#3.0中,引入了一些列新的特性,比如: Implicitly typed local variable, Extension method,Lambda ...

19860
来自专栏大内老A

[原创]深入理解C# 3.x的新特性(3):从Delegate、Anonymous Method到Lambda Expression

在C#3.0中,引入了一些列新的特性,比如: Implicitly typed local variable, Extension method,Lambda ...

22680
来自专栏『不羁阁』 | 行走少年郎专栏

OC知识--彻底理解内存管理(MRC、ARC)

33860
来自专栏程序员互动联盟

【C语言系列】C语言概念--基本数据类型简介

1.概述   C 语言包含的数据类型如下图所示: ? 2.各种数据类型介绍 2.1整型   整形包括短整型、整形和长整形。 2.1.1短整形   short ...

48380

扫码关注云+社区

领取腾讯云代金券