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

发表于:2019-6-18 10:00

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:陈彦斌    来源:博客园

  接口
  先不讲开发中为什么要使用接口?有什么好处?
  假设你是一个修水管的工人,有一个客户让你装水管,但是客户喜欢管子是三角形的。
  很熟练的你就将水管安装到墙上,如图:
  过几天,客户又来找你,他觉得三角形的不好看,要让你把三角形的管子,换成正方形的,你不得不还,因为顾客是上帝,(你会觉得为什么一开始不说要用正方形的管子呢?因为需求一直在变化。)如图:
  哔哩啪啦的累的满头大汗,花费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         }
   开放闭关原则:
  对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
  对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

      上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号