(转帖)对抽象编程:接口和抽象类

[你必须知道的.NET] 第二回:对抽象编程:接口和抽象类

Author:王涛

Date:2007-4-12

©2007 Anytao.com 转贴请注明出处,留此信息。

 本文将介绍以下内容:

  • 面向对象思想:多态
  • 接口
  • 抽象类

1. 引言

在我之前的一篇post 《抽象类和接口的谁是谁非 》中,和同事管伟的讨论,得到很多朋友的关注,因为是不成体系的论道,所以给大家了解造成不便,同时关于这个主题的系统性理论,我认为也有必要做以总结,因此才有了本篇的新鲜出炉。同时,我将把上贴中的问题顺便也在此做以交代。

2. 概念引入

  •       什么是接口?

接口是包含一组虚方法的抽象类型,其中每一种方法都有其名称、参数和返回值。接口方法不能包含任何实现,CLR 允许接口可以包含事件、属性、索引器、静态方法、静态字段、静态构造函数以及常数。但是注意:C# 中不能包含任何静态成员。一个类可以实现多个接口,当一个类继承某个接口时,它不仅要实现该接口定义的所有方法,还要实现该接口从其他接口中继承的所有方法。

定义方法为:

public interface System.IComparable    {        int CompareTo(object o);    }     public class TestCls: IComparable    {        public TestCls()        {        }          private int _value;        public int Value        {            get { return _value; }            set { _value = value; }        }          public int CompareTo(object o)        {             //使用as模式进行转型判断            TestCls aCls = o as TestCls;            if (aCls != null)            {             //实现抽象方法            return _value.CompareTo(aCls._value);            }        }    }
  •        什么是抽象类?

抽象类提供多个派生类共享基类的公共定义,它既可以提供抽象方法,也可以提供非抽象方法。抽象类不能实例化,必须通过继承由派生类实现其抽象方法,因此对抽象类不能使用new 关键字,也不能被密封。如果派生类没有实现所有的抽象方法,则该派生类也必须声明为抽象类。另外,实现抽象方法由overriding 方法来实现。

定义方法为:

/// <summary>/// 定义抽象类/// </summary>abstract public class Animal{    //定义静态字段    protected int _id;      //定义属性    public abstract int Id    {        get;        set;    }      //定义方法    public abstract void Eat();      //定义索引器    public string this[int i]    {        get;        set;    } }  /// <summary>/// 实现抽象类/// </summary>public class Dog: Animal{    public override int Id    {        get {return _id;}        set {_id = value;}    }      public override void Eat()    {        Console.Write("Dog Eats.")    }}

3. 相同点和不同点

3.1 相同点

  • 都不能被直接实例化,都可以通过继承实现其抽象方法。
  • 都是面向抽象编程的技术基础,实现了诸多的设计模式。

3.2 不同点

  • 接口支持多继承;抽象类不能实现多继承。
  • 接口只能定义抽象规则;抽象类既可以定义规则,还可能提供已实现的成员。
  • 接口是一组行为规范;抽象类是一个不完全的类,着重族的概念。
  • 接口可以用于支持回调;抽象类不能实现回调,因为继承不支持。
  • 接口只包含方法、属性、索引器、事件的签名,但不能定义字段和包含实现的方法;抽象类可以定义字段、属性、包含有实现的方法。 
  • 接口可以作用于值类型和引用类型;抽象类只能作用于引用类型。例如,Struct 就可以继承接口,而不能继承类。

 通过相同与不同的比较,我们只能说接口和抽象类,各有所长,但无优略。在实际的编程实践中,我们要视具体情况来酌情量才,但是以下的经验和积累,或许能给大家一些启示,除了我的一些积累之外,很多都来源于经典,我相信经得起考验。所以在规则与场合中,我们学习这些经典,最重要的是学以致用,当然我将以一家之言博大家之笑,看官请继续。

3.3 规则与场合

  • 请记住,面向对象思想的一个最重要的原则就是:面向接口编程。
  • 借助接口和抽象类,23 个设计模式中的很多思想被巧妙的实现了,我认为其精髓简单说来就是:面向抽象编程。
  • 抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。
  • 接口着重于CAN-DO 关系类型,而抽象类则偏重于IS-A 式的关系;
  • 接口多定义对象的行为;抽象类多定义对象的属性; 
  • 接口定义可以使用public 、protected 、internal 和private 修饰符,但是几乎所有的接口都定义为public ,原因就不必多说了。
  •  “ 接口不变” ,是应该考虑的重要因素。所以,在由接口增加扩展时,应该增加新的接口,而不能更改现有接口。
  • 尽量将接口设计成功能单一的功能块,以.NET Framework 为例,IDisposable 、IDisposable 、IComparable 、IEquatable 、IEnumerable 等都只包含一个公共方法。
  • 接口名称前面的大写字母“I” 是一个约定,正如字段名以下划线开头一样,请坚持这些原则。
  • 在接口中,所有的方法都默认为public 。 
  • 如果预计会出现版本问题,可以创建“ 抽象类” 。例如,创建了狗(Dog )、鸡(Chicken )和鸭(Duck ),那么应该考虑抽象出动物(Animal )来应对以后可能出现风马牛的事情。而向接口中添加新成员则会强制要求修改所有派生类,并重新编译,所以版本式的问题最好以抽象类来实现。
  • 从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。
  • 对抽象类不能使用new 关键字,也不能被密封,原因是抽象类不能被实例化。
  • 在抽象方法声明中不能使用 static 或 virtual 修饰符。

以上的规则,我就厚颜无耻的暂定为T14 条吧,写的这么累,就当一时的奖赏吧。大家也可以互通有无,我将及时修订。

4. 经典示例

4.1 绝对经典

.NET Framework 是学习的最好资源,有意识的研究FCL 是每个.NET 程序员的必修课,关于接口和抽象类在FCL 中的使用,我有以下的建议:

  • FCL 对集合类使用了基于接口的设计,所以请关注System.Collections 中关于接口的设计实现;
  • FCL 对数据流相关类使用了基于抽象类的设计,所以请关注System.IO.Stream 类的抽象类设计机制。

4.2 别样小菜

下面的实例,因为是我的理解,因此给经典打上“ 相对” 的记号,至于什么时候晋升为“ 绝对” ,就看我在.NET 追求的路上,是否能够一如既往的如此执着,因此我将把相对重构到绝对为止(呵呵)。 本示例没有阐述抽象类和接口在设计模式中的应用,因为那将是另一篇有讨论价值的文本,本文着眼与概念和原则的把握,但是真正的应用来自于具体的需求规范。

设计结构如图所示:

dd367979.1(zh-cn,MSDN.10).jpg

1. 定义抽象类

public abstract class Animal    {        protected string _name;         //声明抽象属性        public abstract string Name        {            get;        }         //声明抽象方法        public abstract void Show();         //实现一般方法        public void MakeVoice()        {            Console.WriteLine("All animals can make voice!");        }    }

2. 定义接口

public interface IAction    {        //定义公共方法标签        void Move();    }

3. 实现抽象类和接口

public class Duck : Animal, IAction    {        public Duck(string name)        {            _name = name;        }         //重载抽象方法        public override void Show()        {            Console.WriteLine(_name + " is showing for you.");        }         //重载抽象属性        public override string Name        {            get { return _name;}        }         //实现接口方法        public void Move()        {            Console.WriteLine("Duck also can swim.");        }     }     public class Dog : Animal, IAction    {        public Dog(string name)        {            _name = name;        }         public override void Show()        {            Console.WriteLine(_name + " is showing for you.");        }         public override string Name        {            get { return _name; }        }         public void Move()        {            Console.WriteLine(_name + " also can run.");        }     }

4. 客户端实现

public class TestAnmial    {        public static void Main(string [] args)        {            Animal duck = new Duck("Duck");            duck.MakeVoice();            duck.Show();             Animal dog = new Dog("Dog");            dog.MakeVoice();            dog.Show();             IAction dogAction = new Dog("A big dog");            dogAction.Move();        }    }

5. 他山之石

正所谓真理是大家看出来的,所以将园子里有创新性的观点潜列于此,一是感谢大家的共享,二是完善一家之言的不足,希望能够将领域形成知识,受用于我,受用于众。

  • dunai 认为:抽象类是提取具体类的公因式,而接口是为了将一些不相关的类“ 杂凑” 成一个共同的群体。至于他们在各个语言中的句法,语言细节并不是我关心的重点。
  • 桦山涧 的收藏也很不错。
  • Artech 认为:所代码共用和可扩展性考虑,尽量使用Abstract Class 。当然接口在其他方面的优势,我认为也不可忽视。
  • shenfx 认为:当在差异较大的对象间寻求功能上的共性时,使用接口;当在共性较多的对象间寻求功能上的差异时,使用抽象基类。

最后,MSDN 的建议是:

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

6. 结论

接口和抽象类,是论坛上、课堂间讨论最多的话题之一,之所以将这个老话题拿出来再议,是因为从我的体会来说,深刻的理解这两个面向对象的基本内容,对于盘活面向对象的抽象化编程思想至关重要。本文基本概况了接口和抽象类的概念、异同和使用规则,从学习的观点来看,我认为这些总结已经足以表达其核心。但是,对于面向对象和软件设计的深入理解,还是建立在不断实践的基础上,Scott 说自己每天坚持一个小时用来写Demo ,那么我们是不是更应该勤于键盘呢。对于接口和抽象类,请多用而知其然,多想而知其奥吧。

转载于:https://www.cnblogs.com/netstudy0105/archive/2011/03/06/1972423.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/298643.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验四 图的遍历算法设计与实现

一、实验名称&#xff1a;图的遍历算法设计与实现 二、实验目的&#xff1a; 1.掌握图的深度优先遍历的算法。 2.掌握图的广度优先遍历的算法。 3.实验章节&#xff1a;算法设计与分析 第四章 三、实验内容。实验问题和程序运行结果 第一部分 广度优先遍历算法 完善下列程序&am…

为什么魂斗罗只有128KB却可以实现那么长的剧情?

全世界只有3.14 % 的人关注了爆炸吧知识现代程序员A和1980年代游戏程序员B的对话&#xff1a;A&#xff1a;为什么你用128KB能实现这么多画面、音乐、动画&#xff1f;B&#xff1a;128KB还不够么&#xff1f;其实为了表现力已经相当奢侈了&#xff0c;加了很多不重要的细节。A…

asp.net core 6 新特性,支持HTTP/3 端点发布

???? 序言Http3 协议构建在UDP的基础上&#xff0c;是的&#xff0c;就这么神奇&#xff0c;以前被誉为不稳定大神的UDP&#xff0c;现在承担起可靠通讯协议的底层协议。为了消除UDP的不确定性&#xff0c;在UDP协议之上&#xff0c;新增了QUIC协议。使用QUIC协议代替TCP协…

浮点数赋值给整数_初学者专题:变量和赋值

作者&#xff1a;老齐对于初学Python者&#xff0c;除了看书(《跟老齐学Python&#xff1a;轻松入门》或者《Python大学实用教程》&#xff0c;均为电子工业出版社出版)、或者看视频(网易云课堂、CSDN上均有老齐的视频课程)&#xff0c;还要进行专题性总结。比如本文&#xff0…

分析android动画模块[转]

2019独角兽企业重金招聘Python工程师标准>>> 作者: 刘鹏 日期: 2009-03-07 Android 平台提供了两类动画&#xff0c;一类是 Tween 动画&#xff0c;即通过对场景里的对象不断做图像变换(平移、缩放、旋转)产生动画效果&#xff1b;第二类是 Frame 动画&#xff0c;即…

当你的手被502粘住了要怎么做?

1 看清楚&#xff0c;这是大裤衩子▼这才是 jk 裙▼2 天天看你们骂海王男友其实我有一个河神男友▼3 当你的手被502粘住了怎么办&#xff1f;▼4 不能指望食堂阿姨了自己动手丰衣足食▼5 当你被别人夸奖时▼6 宅在家里也能拍大片▼7 是我本人没错了▼你点的每个赞&#…

excel 如何替换带上标的文字_如何在Excel中批量提取中文汉字和英文字母

1. 在数据源的右边分别命名新的两列为“中文名”和“英文名”&#xff0c;然后将数据源复制到“中文名”这一列。2. 为了确保英文名字可以连在一起&#xff0c;这里我们在有空格的英文名字中间添加一个“-”。选择“中文名”下所有数据源&#xff0c;按CtrlF&#xff0c;点击“…

国内最大.NET平台重金招募中 你竟然还不知道?

各位路过的捎带眼瞅见的不小心翻到的英雄好汉请留步~让小编来带你康康这个胆敢号称国内最大的.NET的平台到底有何惊人之处一难道是因为它有--“最敢”的生态开放平台技术驱动商业创新&#xff0c;数字引领企业的未来&#xff0c;明源云通过多年专业积累&#xff0c;融合多种创新…

GChemPaint-绘制化学分子布局

Toy Posted in AppsRSSTrackbackGChemPaint 是专门用来绘制 2D 的化学分子布局软件&#xff0c;它合用于 GNOME 桌面。经由历程它所绘制的化学分子布局可以被嵌入到其他的应用程序中。Download GChemPaint 0.7.91版权声明&#xff1a; 原创作品&#xff0c;允许转载&#xff0c…

软件开发有哪些规范和标准_深圳APP软件开发的流程是什么?

深圳APP软件开发的流程是什么&#xff1f;APP软件开发是根据用户需求构建软件系统或设备的软件部分的过程&#xff0c;是一项系统工程&#xff0c;包括需求捕获&#xff0c;需求分析&#xff0c;系统设计&#xff0c;系统实现和系统测试。APP软件通常以某种编程语言实现&#x…

第十六周项目3-有相同数字?

输入两个数组中要存放的元素个数及元素值&#xff08;不超过50个&#xff09;&#xff0c;判断这两个数组中是否有相同的数字。 当两组数中有相同数字时&#xff0c;输出YES&#xff0c;否则&#xff0c;输出NO /* * Copyright (c) 2014,烟台大学计算机学院 * All right reserv…

一键对频对讲机好吗_对讲机的基础知识你都知道多少呢?

对讲机或PMR是手持式便携式无线电&#xff0c;可在单个共享频带上使用无线电波进行无线通信。这使Walkie Talkies成为以低成本与大范围人群保持联系的最有效方法之一。双向无线电功能强大&#xff0c;易于使用且易于使用。它们特别适合在户外或在手机或平板电脑过于精致或超出信…

女儿学会走路了,是不是该教她学Python了?

1 哈哈哈&#xff0c;20个人其实都是精准客户▼2 搬沙发一定不要穿的太正式&#xff01;▼3 横竖都是死让我先打完这场游戏先▼4 只要你学会这支舞你就是你妈的好朋友▼5 你能体会到这只阿拉斯加的惆怅吗&#xff1f;▼6 这双鞋一看就是全球限量有钱都买不到的那种▼7 我…

html游戏怎么做,HTML5 制做“游戏”的一个基本流程

怎样用HTML5 Canvas制作一个简单的游戏为了让大家清楚HTML5制作游戏的简单流程&#xff0c;所以先了制作一个非常简单的游戏&#xff0c;来看一看这个过程。游戏非常简单&#xff0c;无非就是英雄抓住怪物就得分&#xff0c;然后游戏重新开始&#xff0c;怪物出现在地图的随机位…

.NET 6 的 docker 镜像可以有多小

.NET 6 的 docker 镜像可以有多小?Intro最近写了一个小玩具&#xff0c;一个命令行调用 HTTP API 的工具&#xff0c;介绍可以参考&#xff1a;动手造轮子 —— dotnet-HTTPie&#xff0c;最近在使用 System.CommandLine 重构的同时&#xff0c;也在尝试减少 docker 镜像的大小…

开源播放器 Banshee 发布 1.0 beta 2

Banshee也是个很是不错的开源播放器,同时也是SuSE的内置播放器,默许支持靠山播放,消息区域告诉,可以快速跳过以后曲目,评分等等,也支持全局热键,媒体库支持音频和视频.新版本提供了对网络视频和PodCast的优秀支持.SuSE/Ubuntu/Fedora Linux用户可以从源中直接安置,也可以下载安…

仓库每天的账怎样做_新年第一站,济南:仓储匠人仓库问题解决与实战力培训...

【时间地点】1月15-16日&#xff0c;济南站济南市天桥区无影山北路88号祥云酒店5楼(师范路西口)【报名方式】直接加微信号“taishan33976”&#xff0c;注明姓名公司名仓储匠人。如果您认识小编的任意一位同事&#xff0c;欢迎直接找他们报名。【培训价格】1960元/人&#xff0…

一对一指导怎么追喜欢的男生

1 它们是怎样达成平衡的2 OK. 对不起打扰了3 今天也要加油鸭&#xff01;4 以色列一个父亲&#xff0c;为她“坐没坐相”的女儿打造的椅子。5 这个床我爱了6 静冈花火大会上摄影师发现了一个有趣的角度7 怎么样学会了吗内容自奔现翻车现场你点的每个赞&#xff0c;我都认真当成…

android canvas_Android 如何实现气泡选择动画

作者&#xff1a;Irina Galata Android 开发者: Yulia Serbenenko UI/UX 设计师 译者&#xff1a;skyar2009链接&#xff1a;https://juejin.im/post/58e5ec838d6d8100616d82e2/跨平台用户体验统一正处于增长趋势&#xff1a;早些时候 iOS 和安卓有着不同的体验&#xff0c;但是…

MVC中的验证规则

前面的博客中曾经提到过ModelBing机制&#xff0c;也在Demo中体现过&#xff0c;在MVC中更吊的是封装了自定义的验证规则。下面来一个Demo来展现一下&#xff0c;看了后&#xff0c;你一定会爱上它的&#xff0c;能让你少写很多JS语句。 1.View层 [html] view plaincopyprint…