生活小例子,通俗易懂讲接口
接口
注:本篇文字约4300字,可能花费10分钟。
先不讲开发中为什么要使用接口?有什么好处?
假设你是一个修水管的工人,有一个客户让你装水管,但是客户喜欢管子是三角形的。
很熟练的你就将水管安装到墙上,如图:
过几天,客户又来找你,他觉得三角形的不好看,要让你把三角形的管子,换成正方形的,你不得不还,因为顾客是上帝,(你会觉得为什么一开始不说要用正方形的管子呢?因为需求一直在变化。。。)如图:
哔哩啪啦的累的满头大汗,花费2 3个小时才将管子换成正方形的。没过多久,客户又来找你,这次客户想要换个椭圆形的管子。虽然很无奈,顾客是上帝,又花费几个小时换好管子,如图:
这时你可能会想,为什么换不同形状的水管,需要大动干戈一番呢?刚开始的时候,可以在墙上设计一个固定的水管,并且是圆形的,根据客户的喜好更换不同的水管。这样,以后都不用去动墙上的水管了。这个方法好!~~这就叫做接口,如图:
这里,我查阅了一下百度百科给接口最权威的定义。
接口:是指定一组函数成员而不实现成员的引用类型,其他类型-类和结构可以实现接口。
换句话说:接口没有具体实现,他只是一种行为约束规范,需要子类继承该接口来实现方法。
这就是为什么小白们会觉得接口什么都不做,只定义一个接口,没有任何实现,那不多此一举么?
下面我们在代码中体现接口的作用,再次声明,不讨论场景是否合情合理~~~
需求:公司有两个人分别写了两个国家的母语类,来输出该国的母语,你来负责调用他们写好的类。
1 class China //中国 2 { 3 public void Speak() 4 { 5 Console.WriteLine("我们国家说中国话!~"); 6 } 7 } 8 class America //美国 9 { 10 public void Speak() 11 { 12 Console.WriteLine("我们国家说英语!~"); 13 } 14 }
你写的Country类
1 class Country 2 { 3 public void show(China china) 4 { 5 china.Speak(); 6 } 7 public void show(America america) 8 { 9 america.Speak(); 10 } 11 }
调用
1 static void Main(string[] args) 2 { 3 Country c = new Country(); 4 c.show(new China()); 5 c.show(new America()); 6 Console.ReadKey(); 7 }
过了一段时间,公司业务变了,需要增加一个俄罗斯类,暂且叫C吧,让C去写这个,并调用
1 class China //中国 2 { 3 public void Speak() 4 { 5 Console.WriteLine("我们国家说中国话!~"); 6 } 7 } 8 class America //美国 9 { 10 public void Speak() 11 { 12 Console.WriteLine("我们国家说英语!~"); 13 } 14 } 15 class Russia //俄罗斯 16 { 17 public void Speak() 18 { 19 Console.WriteLine("我们国家说俄语!~"); 20 } 21 }
于是你的Country类,又多了一个方法重载:
1 class Country 2 { 3 public void show(China china) 4 { 5 china.Speak(); 6 } 7 public void show(America america) 8 { 9 america.Speak(); 10 } 11 public void show(Russia russia) 12 { 13 russia.Speak(); 14 } 15 }
调用
1 static void Main(string[] args) 2 { 3 Country c = new Country(); 4 c.show(new China()); //我们国家说中国话!~ 5 c.show(new America()); //我们国家说英语!~ 6 c.show(new Russia()); //我们国家说俄语!~ 7 Console.ReadKey(); 8 }
细心的你已经发现,多一个类,就多一个方法的重载,世界上还有怎么多的国家,以后增加一个,Country类就要修改一次,显然不是什么好事!
我们仔细观察Country类,不变的是show方法,变化的是show方法中的参数,如果有那么一个类,能接收所有世界各国,问题不就解决了嘛?聪明的你可能想到了重载,定义一个Person父类,让子类去继承,里面有个show方法。
终极代码
1 static void Main(string[] args) 2 { 3 Country c = new Country(); 4 c.show(new China()); //我们国家说中国话!~ 5 c.show(new America()); //我们国家说英语!~ 6 c.show(new Russia()); //我们国家说俄语!~ 7 Console.ReadKey(); 8 } 9 class China : Person //中国 10 { 11 public China() : base() //子类构造方法需要调用父类同样参数类型的构造函数,用base关键字代表父类 12 { 13 14 } 15 public override void Speak() //注意增加了override,表示方法重写 16 { 17 Console.WriteLine("我们国家说中国话!~"); 18 } 19 } 20 class America : Person //美国 21 { 22 public America() : base() //子类构造方法需要调用父类同样参数类型的构造函数,用base关键字代表父类 23 { 24 25 } 26 public override void Speak() //注意增加了override,表示方法重写 27 { 28 Console.WriteLine("我们国家说英语!~"); 29 } 30 } 31 class Russia:Person //俄罗斯 32 { 33 public Russia() : base() //子类构造方法需要调用父类同样参数类型的构造函数,用base关键字代表父类 34 { 35 36 } 37 public override void Speak() //注意增加了override,表示方法重写 38 { 39 Console.WriteLine("我们国家说俄语!~"); 40 } 41 } 42 class Country 43 { 44 public void show(Person person) 45 { 46 person.Speak(); 47 } 48 } 49 class Person 50 { 51 public virtual void Speak() // 注意修饰符中增加了一个virtual,它表示此方法是虚方法,可以被子类重写 52 { 53 Console.WriteLine("我是Person父类"); 54 } 55 }
不管以后还有什么国家的类,只要让需要添加的国家类,继承Person,并且有个Speak方法,那么就不用修改Country类了,只需要传入一个国家类的实例即可。
有一天,公司新来一个人,暂且叫D吧,现在让D写一个France(法国类),并且继承Person类,里面有个母语的方法。
D写的类如下:
1 class France : Person //法国 2 { 3 public France() : base() 4 { 5 6 } 7 public void MotherLanguage() 8 { 9 Console.WriteLine("我们国家说法语!~"); 10 } 11 }
调用
1 static void Main(string[] args) 2 { 3 Country c = new Country(); 4 c.show(new China()); //我们国家说中国话!~ 5 c.show(new America()); //我们国家说英语!~ 6 c.show(new Russia()); //我们国家说俄语!~ 7 c.show(new France()); //我是Person父类 8 Console.ReadKey(); 9 }
很显然不是我们想要的输出结果,你不得不花点时间去排查原因,最后你发现原来D虽然写了。
France类,但是他并不知道之前约定的命名为:Speak()
D写的France类中,里面的方法是:MotherLanguage()
细心的童鞋们已经发现问题的关键了,虽然D继承了Person类,但是没有一种约束,使其继承父类的时候必须实现父类中的方法。有没有一个类,能让它的子类必须实现它定义的方法???
有,那就是接口。
接口如下:
1 interface Person 2 { 3 void Speak(); 4 }
由于Person接口有一个Speak()方法,所有子类继承接口的类,必须实现该方法,否则程序不能通过。
这时你再想想,虽然继承一个父类也可以满足要求,但是一个父类根本没有约束力,而接口就不一样了,子类继承接口,必须实现接口中的所有方法。
在多人协作下,定义一系列方法,让子类必须继承该接口,防止在调用一个人写的子类时,找不到方法。
最终完整代码
1 static void Main(string[] args) 2 { 3 Country c = new Country(); 4 c.show(new China()); //我们国家说中国话!~ 5 c.show(new America()); //我们国家说英语!~ 6 c.show(new Russia()); //我们国家说俄语!~ 7 c.show(new France()); //我们国家说法语!~ 8 Console.ReadKey(); 9 } 10 class China : Person //中国 11 { 12 public void Speak() //注意增加了override,表示方法重写 13 { 14 Console.WriteLine("我们国家说中国话!~"); 15 } 16 } 17 class America : Person //美国 18 { 19 public void Speak() //注意增加了override,表示方法重写 20 { 21 Console.WriteLine("我们国家说英语!~"); 22 } 23 } 24 class Russia : Person//俄罗斯 25 { 26 public void Speak() //注意增加了override,表示方法重写 27 { 28 Console.WriteLine("我们国家说俄语!~"); 29 } 30 } 31 class France : Person //法国 32 { 33 public void Speak() 34 { 35 Console.WriteLine("我们国家说法语!~"); 36 } 37 } 38 class Country 39 { 40 public void show(Person person) 41 { 42 person.Speak(); 43 } 44 } 45 interface Person 46 { 47 void Speak(); 48 }
开放闭关原则: