生活小例子,通俗易懂讲接口

接口

注:本篇文字约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         }

开放闭关原则:

  对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

 

posted @ 2019-06-14 00:34  陈彦斌  阅读(1121)  评论(11编辑  收藏  举报