[.net 面向对象编程基础] (16) 接口

[.net 面向对象编程基础] (16) 接口

关于“接口”一词,跟我们平常看到的电脑的硬件“接口”意义上是差不多的。拿一台电脑来说,我们从外面,可以看到他的USB接口,COM接口等,那么这些接口的目的一就是让第三方厂商生产的外设都有相同的标准,也是提供一个对外通信或操作的入口。

只是C#的接口除了以上特点之外,还具有一种类似于模板的功能,我们定义一组接口,就像是一个模板。这点和抽象类不同,抽象类是先有子类或都子类的概念,从中抽象出一个类。而接口更像是我们要设计一台机器,先把这台机器对外的功能接口列出来,然后再做具体的实现,当然这个说法是站在软件设计的角度来讲的。

1.什么是接口?

接口就是把隐式公共方法和属性组合起来,以封装特定功能的一个集合。

接口简单理解就是一种约定,使得实现接口的类或结构在形式上保持一致。

接口描述的是可属于任何类或结构的一组相关功能,所以实现接口的类或结构必须实现接口定义中指定的接口成员。

接口使用interface 关键字进行定义,可由方法、属性、事件、索引器或这四种成员类型的任意组合构成。

接口的名称,通常使用I开头(按规范命名很重要)

2、接口的特性

A.接口类似于抽象基类,不能直接实例化接口;接口中的方法都是抽象方法,实现接口的任何非抽象类型都必须实现接口的所有成员:

当显式实现该接口的成员时,实现的成员不能通过类实例访问,只能通过接口实例访问。

当隐式实现该接口的成员时,实现的成员可以通过类实例访问,也可以通过接口实例访问,但是实现的成员必须是公有的。

B.接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型、不能包含静态成员。

C.接口成员是自动公开的,且不能包含任何访问修饰符。

D.接口自身可从多个接口继承,类和结构可继承多个接口,但接口不能继承类。

3.接口和抽象类的区别:

接口用于规范,抽象类用于共性。

接口中只能声明方法,属性,事件,索引器。而抽象类中可以有方法的实现,也可以定义非静态的类变量。

抽象类是类,所以只能被单继承,但是接口却可以一次实现多个。

抽象类可以提供某些方法的部分实现,接口不可以。

抽象类的实例是它的子类给出的。接口的实例是实现接口的类给出的。

在抽象类中加入一个方法,那么它的子类就同时有了这个方法。而在接口中加入新的方法,那么实现它的类就要重新编写(这就是为什么说接口是一个类的规范了)。

接口成员被定义为公共的,但抽象类的成员也可以是私有的、受保护的、内部的或受保护的内部成员(其中受保护的内部成员只能在应用程序的代码或派生类中访问)。

此外接口不能包含字段、构造函数、析构函数、静态成员或常量。

抽象类可以包含一些成员的实现,接口却不包含成员的实现;抽象类的抽象成员可以被子类实现,而接口的的成员需要实现类完全实现;一个类可能继承一个抽象类,但是可以实现多个接口。

4.接口和抽象类在设计角度的异同

上面说了接口和抽象类在表象上或说是形态上的区别,此外接口和抽象类在设计过程中也有很多不同之处,这也就是C#为何设计了抽象类还要设计接口的原因。即他们使用场合的不同。

第一、类是对对象的抽象;抽象类是对类的抽象;接口是对行为的抽象;

第二、如果行为跨越不同类的对象,可使用接口;对于一些相似的对象使用继承抽象类;

第三、从设计角度讲,抽象类是从子类中发现了公共的东西,泛化出父类,然后子类继承父类;而接口跟本不知道子类的存在,方法如何实现还不确认,即预先定义。

在实际项目中,抽象类往往是通过重构产生,除非你事先知道某类有很多子类要实现,从而抽象出抽象类,即自底而上设计。接口则是在项目设计之初就确实要实现那些行为,属于自顶向下设计。

5.代码示例

通过上面的学习,我们知道了抽象类和接口的区别以及他们在设计角度的使用。下面,我们按国际惯例重新设计我们的动物类(Animal)以及他们的子类狗(Dog)、猫(Cat)、羊(Sheep)假如我们事先知道有一种羊“喜羊羊”(PleasantSheep)和一种猫“蓝猫”(BlueCat)他们有一个共同的行为就是会说话,这时候,我们肯定会想到给他们的抽象类Animal定义一个抽象方法说话(Speak),哈哈,傻了吧,犯错了吧,动物都可以讲话么?为了解决这种事例,我们需要用到接口,我们事先知道有一个“讲话”这个行为,那么我就定义一个讲话的接口(ISpeak).UML图如下

下面看一下代码:

  1 /// <summary>
  2 /// 动物类(父类 抽象类)
  3 /// </summary>
  4 abstract class Animal
  5 {
  6     /// <summary>
  7     /// 名字
  8     /// 说明:类和子类可访问
  9     /// </summary>
 10     protected string name;
 11
 12     /// <summary>
 13     /// 构造函数
 14     /// </summary>
 15     /// <param name="name"></param>
 16     public Animal(string name)
 17     {
 18         this.name = name;
 19     }
 20
 21     private int shoutNum = 3;
 22     public int ShoutNum
 23     {
 24         get { return shoutNum; }
 25         set { shoutNum = value; }
 26     }
 27
 28     /// <summary>
 29     /// 名字(虚属性)
 30     /// </summary>
 31     public virtual string MyName
 32     {
 33         get { return this.name; }
 34     }
 35
 36     /// <summary>
 37     /// 叫声,这个方法去掉虚方法,把循环写在这里
 38     /// </summary>
 39     public void Shout()
 40     {
 41         string result = "";
 42         for (int i = 0; i < ShoutNum; i++)
 43             result += getShoutSound() + "!";
 44
 45         Console.WriteLine(MyName);
 46         Console.WriteLine(result);
 47     }
 48
 49     /// <summary>
 50     /// 创建一个叫声的虚方法,子类重写
 51     /// </summary>
 52     /// <returns></returns>
 53     public virtual string getShoutSound()
 54     {
 55         return "";
 56     }
 57 }
 58
 59 /// <summary>
 60 /// 声明一个接口 ISpeak(讲话)
 61 /// </summary>
 62 interface ISpeak
 63 {
 64     void Speak();
 65 }
 66
 67 /// <summary>
 68 /// 狗(子类)
 69 /// </summary>
 70 class Dog : Animal
 71 {
 72     string myName;
 73     public Dog(string name): base(name)
 74     {
 75         myName = name;
 76     }
 77     /// <summary>
 78     /// 名字(重写父类属性)
 79     /// </summary>
 80     public override string MyName
 81     {
 82         get { return "我是:狗狗,我叫:" + this.name; }
 83     }
 84     /// <summary>
 85     /// 叫(重写父类方法)
 86     /// </summary>
 87     public override string getShoutSound()
 88     {
 89         return "汪!";
 90     }
 91 }
 92
 93
 94 /// <summary>
 95 /// 猫(子类)
 96 /// </summary>
 97 class Cat : Animal
 98 {
 99     string myName;
100     public Cat(string name): base(name)
101     {
102         myName = name;
103     }
104     /// <summary>
105     /// 名字(重写父类属性)
106     /// </summary>
107     public override string MyName
108     {
109         get { return "我是:猫咪,我叫:" + this.name; }
110     }
111     /// <summary>
112     /// 叫(重写父类方法)
113     /// </summary>
114     public override string getShoutSound()
115     {
116         return "喵!";
117     }
118 }
119
120 /// <summary>
121 /// 蓝猫(子类)
122 /// 继承 Cat和接口ISpeak
123 /// </summary>
124 class BlueCat : Cat,ISpeak
125 {
126     string myName;
127     public BlueCat(string name) : base(name)
128     {
129         myName = name;
130     }
131     /// <summary>
132     /// 名字(重写父类属性)
133     /// </summary>
134     public override string MyName
135     {
136         get { return "我是:蓝猫,我叫:" + this.name; }
137     }
138
139     /// <summary>
140     /// 实现接口ISpeak的成员Speak
141     /// </summary>
142     public void Speak()
143     {
144         Console.WriteLine("我会说人话:“你好,我叫:" + this.name + "~~~”");
145     }
146 }
147
148
149 /// <summary>
150 /// 羊(子类)
151 /// </summary>
152 class Sheep : Animal
153 {
154     string myName;
155     public Sheep(string name): base(name)
156     {
157         myName = name;
158     }
159     /// <summary>
160     /// 名字(重写父类属性)
161     /// </summary>
162     public override string MyName
163     {
164         get { return "我是:羊羊,我叫:" + this.name; }
165     }
166     /// <summary>
167     /// 叫(重写父类方法)
168     /// </summary>
169     public override string getShoutSound()
170     {
171         return "咩!";
172     }
173 }
174
175 /// <summary>
176 /// 喜羊羊(子类)
177 /// 继承 Sheep和接口ISpeak
178 /// </summary>
179 class PleasantSheep : Sheep, ISpeak
180 {
181     string myName;
182     public PleasantSheep(string name) : base(name)
183     {
184         myName = name;
185     }
186     /// <summary>
187     /// 名字(重写父类属性)
188     /// </summary>
189     public override string MyName
190     {
191         get { return "我是:喜羊羊,我叫:" + this.name; }
192     }
193     /// <summary>
194     /// 实现接口ISpeak的成员Speak
195     /// </summary>
196     public void Speak()
197     {
198         Console.WriteLine("我会说人话:“你好,我叫:" + this.name + "~~~”");
199     }
200 }

调用一:

//喜羊羊来了出场了
Animal pleasantSheep = new PleasantSheep("最帅喜羊羊");
pleasantSheep.Shout();
ISpeak IPleasantSheepSpeak= new PleasantSheep("最帅喜羊羊");
IPleasantSheepSpeak.Speak();
Console.ReadLine();
//结果如下:
//我是:喜羊羊,我叫:最帅喜羊羊
//咩!!咩!!咩!!
//我会说人话:“你好,我叫:最帅喜羊羊~~~”

调用二:

//蓝猫出场了
Animal blueCat = new BlueCat("最美蓝猫");
blueCat.Shout();
ISpeak IBlueCatSpeak = new PleasantSheep("最美蓝猫");
IBlueCatSpeak.Speak();
Console.ReadLine();
//结果如下:
//我是:蓝猫,我叫:最美蓝猫
//喵!!喵!!喵!!
//我会说人话:“你好,我叫:最美蓝猫~~~”

6.要点:

A.接口简单理解就是一种约定,使得实现接口的类或结构在形式上保持一致

B.接口的类可以实现方法、属性、事件、索引器这四种类型,不能实现委托。后面要说,委托是一种类型,而接口成员非类型。

C.接口中的成员用来定义对象之间通信的契约,指定接口中的成员为私有或保护没有意义。它们默认为公有。

D.接口可以继承多个接口,但不能继承类

E.类可以继承多个接口,但不能继

F.接口和类有什么异同:

异:

不能直接实例化接口。

接口不包含方法的实现。

接口可以实现多继承,而类只能是单继承。

类定义可在不同的源文件之间进行拆分。

同:

接口、类和结构可从多个接口继承。

接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。

接口可以包含事件、索引器、方法和属性。

一个类可以实现多个接口。

==============================================================================================

返回目录 <如果对你有帮助,记得点一下推荐哦,有不明白的地方或写的不对的地方,请多交流>

==============================================================================================

时间: 2024-11-14 19:38:45

[.net 面向对象编程基础] (16) 接口的相关文章

[.net 面向对象编程基础] (20) LINQ使用

[.net 面向对象编程基础] (20)  LINQ使用 通过上节LINQ的基础知识的学习,我们可以开始使用LINQ来进行内存数据的查询了,我们上节说了LINQ的定义为:Language Integrated Query(语言集成查询)的简称,它是集成在.NET编程语言中的一种特性. 1.LINQ的构架 从这幅图中,我们可以知道LINQ包括五个部分:LINQ to Objects.LINQ to XML.LINQ to SQL.LINQ to DataSet.LINQ to Entities.

[.net 面向对象编程基础] (14) 重构

[.net 面向对象编程基础] (14) 重构 通过面向对象三大特性:封装.继承.多态的学习,可以说我们已经掌握了面向对象的核心.接下来的学习就是如何让我们的代码更优雅.更高效.更易读.更易维护.当然了,这也是从一个普通程序员到一个高级程序员的必由之路.就看病一样,普通医生只能治标,高级医生不但看好病,还能除病根. 1.什么时重构? 重构(Refactoring)就是在不改变软件现有功能的基础上,通过调整程序代码改善软件的质量.性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性.

[.net 面向对象编程基础] (17) 数组与集合

[.net 面向对象编程基础] (17) 数组与集合 学习了前面的C#三大特性,及接口,抽象类这些相对抽象的东西以后,是不是有点很累的感觉.具体的东西总是容易理解,因此我们在介绍前面抽象概念的时候,总是举的是具体的实例以加深理解. 本节内容相当具体,学起来也相当轻松. 1.数组 1.1 什么是数组? 数组是一种数据结构,包含同一个类型的多个元素. 1.2数组的初始化 string[] mystringArray; 类型+方框号 数组名 1.3数组初始化 我们知道数组是引用类型,所以需要给他分配堆

[.net 面向对象编程基础] (18) 泛型

[.net 面向对象编程基础] (18) 泛型 上一节我们说到了两种数据类型数组和集合,数组是指包含同一类型的多个元素,集合是指.net中提供数据存储和检索的专用类. 数组使用前需要先指定大小,并且检索不方便.集合检索和声明方便,但是存在类型安全问题,本来使一个类型安全的C#变得不安全了. 集合为了解决数组预设大小的问题,采取了一种自动扩容的办法,这样当大小不够时,他就创建一个新的存储区域,把原有集合的元素复制过来.如此又对性能上也是有很大的影响. 上节我们说到解决这些缺陷的方法,那就是.NET

[.net 面向对象编程基础] (15) 抽象类

[.net 面向对象编程基础] (15) 抽象类 前面我们已经使用到了虚方法(使用 Virtual修饰符)和抽象类及抽象方法(使用abstract修饰符)我们在多态一节中说到要实现类成员的重写必须定义为一个虚方法或抽象方法.这节单独把抽象类提出来,是因为抽象是.net实现面向对象编程重要的重要思想,定义抽象类就象一个模板一个提纲,它可以理解为中央的指导思想,我们通过派生类去具体实现它.由此可见,抽象类本身没有任何作用,也不能被实例化,因为他本身就不具有具体的事物.比如上节的动物类的例 子,我们实

[.net 面向对象编程基础] (11) 面向对象三大特性——封装

[.net 面向对象编程基础] (11) 面向对象三大特性——封装 我们的课题是面向对象编程,前面主要介绍了面向对象的基础知识,而从这里开始才是面向对象的核心部分,即 面向对象的三大特性:封装.继承.多态. 1.封装概念 封装:每个对象都包含有它能进行操作的所有信息,这个特性称为封装.这样的方法包含在类中,通过类的实例来实现. 2.封装的优点 A.良好的封装能够减少耦合(比如实现界面和逻辑分离) B.可以让类对外接口不变,内部可以实现自由的修改 C.类具有清晰的对外接口,使用者只需调用,无需关心

JAVA学习(五):Java面向对象编程基础

Java面向对象编程基础 面向对象(Object oriented programming,OOP)技术是一种强有力的软件开发方法,它採用数据抽象与信息隐藏技术,来使软件开发简单化,以达到代码重用的目的. 1.OOP的3个特性(封装.继承和多态性) 封装是类的基础.指把类的相关实现细节隐藏起来,在类中将数据和实现操作的代码集中起来放在对象的内部.调用这些类时仅仅需直接使用类预留的接口就能够了. 继承提供了子类自己主动拥有父类数据结构和方法的机制.它表示类之间的一种关系. 多态指使一个对象被看成还

[.net 面向对象编程基础] (22) 事件

[.net 面向对象编程基础] (22)  事件 事件(Event)是学习.net面向对象编程很重要的一部分,在学习事件之前,我们实际上已经在很多地方使用了事件,比如控件的click事件等,这些都是.net设计控件的时候已经定义好的事件.除此之外,我们同样可以自己定义事件. 事件实际上是一种消息机制,当然点击控件时,click就通知处理他的方法去处理,实际上就是前面说的委托.因此我们可以说:事件是一种具有特殊签名的委托.而事件/消息机制是windows的核心,因此我们必须掌握他. 为了更加容易理

[.net 面向对象编程基础] (21) 委托

[.net 面向对象编程基础] (20)  委托 上节在讲到LINQ的匿名方法中说到了委托,不过比较简单,没了解清楚没关系,这节中会详细说明委托. 1.什么是委托? 学习委托,我想说,学会了就感觉简单的不能再简单了,没学过或都不愿了解的人,看着就头大,其实很简单.委托在.net面向对象编程和学习设计模式中非常重要,是学习.net面向对象编程必须要学会并掌握的. 委托从字面上理解,就是把做一些事情交给别人来帮忙完成.在C#中也可以这样理解,委托就是动态调用方法.这样说明,就很好理解了. 平时我们会