系列文章索引:《白话C#》
接口是体现面向对象编程思想优越性的一件利器,为什么这么说呢?首先我们来看,接口是为继承而存在的,如果没有继承,那就自然不需要接口了,既然有继承,那就需要把可能被多个类所继承的一些公共部分抽象出来,接口封装的就是这些公共的行为规范(方法定义),类可以通过继承多个接口来丰富自己的行为机制,但是在C#中,类是不可以继承多个类的。C#最显著的特点就是极大地提高了程序的开发效率和维护效率,所以对于继承多个类这种容易引起二义性的机制是深恶痛绝的。
我们都是由学生时代一路走过来的,所以我想借用学生时代的那些行为规范来作为现实生活中的接口的例子。
读小学的时候,我们至少会有两套行为规范:小学生行为规范和少先队员行为规范。首先我们都得遵守小学生行为规范,其次如果是少先队员,就还得遵守少先队员行为规范。我们对于这两套行为规范不列举太多细节规则,每套一条就够了,首先,作为少先队员,过马路时要先看红绿灯:
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: