接口只是定义了类必须做什么,而不是怎么作。接口和类的区别:
(1)接口只提供类所需实现的方法、属性、索引或事件的格式或约定,不提供任何相应的功能代码
(2)接口中的所有成员被视为共有,不能有任何访问修饰符。
(3)要实现接口必须实现接口种的所有成员。
(4)接口允许多重继承。
我们都是由学生时代一路走过来的,所以我想借用学生时代的那些行为规范来作为现实生活中的接口的例子。
读小学的时候,我们至少会有两套行为规范:小学生行为规范和少先队员行为规范。首先我们都得遵守小学生行为规范,其次如果是少先队员,就还得遵守少先队员行为规范。我们对于这两套行为规范不列举太多细节规则,每套一条就够了,首先,作为少先队员,过马路时要先看红绿灯:
1: interface IPupilRule
2: {3: void CrossTheRoad(int trafficLightIndex);
4: }在IPupileRule中,我们定义了“过马路看红绿灯”这样的行为规范,它其实就是一个函数声明,定义了函数名、返回值类型以及参数类型等信息,但是并没有函数体。对,接口中只能有函数定义这样的指导性原则,不允许存在函数体,至于具体的实现细节,那就“具体问题具体分析”吧。接下来我们再来定义少先队员行为规范,也不列举太多细则,一条足矣,少先队员不能抽烟:
1: interface IYoungPioneerRule
2: {3: void NoSmoke();
4: }同样的,只有函数声明没有实现细节,因为行为守则这样的东西只能告诉你作为一名光荣的少先队员是绝对不能抽烟的,它不会也不能面面俱到地告诉你假如你叔叔阿姨给你递烟应该如何谢绝,假如你爸爸教你抽烟应该如何拒绝,另外假如那些辍学的坏孩子强迫你抽烟又该如何反抗等等。废话不多说,否则真成了“提供函数体的接口”了。
既然接口是不提供函数实现细节的,那么当一个小学生需要横过马路的时候,就只能靠他自己来完成具体的逻辑实现了:
1: public class Pupil : IPupilRule
2: {3: /// <summary>
4: /// Cross the road and notice the traffic light.
5: /// </summary>
6: /// <param name="trafficLightIndex">The index of traffic light.</param>
7: public void CrossTheRoad(int trafficLightIndex)
8: {9: switch (trafficLightIndex)
10: {11: case 0: // Red, stop.
12: break;
13: case 1: // Yellow, stop.
14: break;
15: case 2: // Green, go.
16: break;
17: default: // Unknown situation, thinking.
18: break;
19: } 20: } 21: }接下来,少先队员出场了。首先我们来分析一下这个场景,少先队员是需要遵守少先队员行为规范的小学生。由此可见,少先队员需要实现前面提到的两种行为规范中的所有规定,这也就体现了接口的好处,可以实现多重继承。当然,在本文所用的例子当中,少先队员大可不必重新继承并实现IPupilRule接口了,他既然是一名小学生,那就可以继承Pupil这个类,而且他并不需要改变Pupil中对小学生行为规范的具体实现细节,他只需要自己实现少先队员行为规范中的规定就行了。
1: public class YoungPioneer : Pupil, IYoungPioneerRule
2: {3: /// <summary>
4: /// Young pioneer should help other people.
5: /// </summary>
6: public void NoSmoke()
7: {8: throw new NotImplementedException("I can't smoke because I'm a young pioneer.");
9: } 10: }另外,接口也是可以继承接口的,并且可以多重继承。我们假设有一个向阳小学,这个学校还有自己的校规,校规内容不多,主要是要求学生要严格遵守小学生行为规范和少先队员行为规范,并且都要会唱校歌。
1: interface IXiangYangSchoolRule : IPupilRule, IYoungPioneerRule
2: {3: void SingSchoolSong();
4: }因此这套校规编写起来倒不麻烦,继承了两套现成的行为规范并且增加一点儿自己的要求就行了。向阳小学的每一位学生都得遵守这套校规:
1: public class XiangYangPupil : IXiangYangSchoolRule
2: {3: public void SingSchoolSong()
4: {5: Console.WriteLine("I love Xiang Yang School!");
6: } 7: 8: public void CrossTheRoad(int trafficLightIndex)
9: {10: throw new NotImplementedException();
11: } 12: 13: public void NoSmoke()
14: {15: throw new NotImplementedException();
16: } 17: }1: interface IPupilRule
2: {3: void NoSmoke();
4: }
public class YoungPioneer:IPupilRule,IYoungPioneerRule
{
void IPupilRule.NoSmoke()//显式实现是私有成员,不能用public修饰
{
Console.WriteLine("I am a Pupil");
}
void IYoungPioneerRule.NoSmoke()
{
Console.WriteLine("I am a YoungPioneer");
}
}
public class MyApp
{
public static void Main()
{
YoungPioneer y = new YoungPioneer();
IPupilRule pupil = (IPupilRule)y;
IYoungPioneerRule young = (IYoungPioneerRule)y;
pupil.NoSmoke();
young.NoSmoke();
}
}
以上使用了方法的完全限定名,在同一个类中显式得实现了两个接口中同名方法的调用,对显式方法的调用不能使用类名.方法的格式,要调用不同接口的某个方法时,常用两个方法:
(1)将类对象强制转换为接口变量。
(2)在实现方法的类中,分别显式实现两个同名方法,由于显式实现方法是私有的,所以在类中在相应创建两个用于对这两个方法进行调用的方法。称为接口引用调用方法。
public class YoungPioneer:IPupilRule,IYoungPioneerRule
{
void IPupilRule.NoSmoke()//显式实现是私有成员,不能用public修饰
{
Console.WriteLine("I am a Pupil");
}
void IYoungPioneerRule.NoSmoke()
{
Console.WriteLine("I am a YoungPioneer");
}
public void NoSmoke_A()
{
IPupilRule p = this;
p.NoSmoke();
}
public void NoSmoke_B()
{
IYoungPioneerRule y = this;
y.NoSmoke();
}
}
public class MyApp
{
public static void Main()
{
YoungPioneer y = new YoungPioneer();
y.NoSmoke_A();
y.NoSmoke_B();
}
}
浙公网安备 33010602011771号