zoukankan      html  css  js  c++  java
  • 生活小例子,通俗易懂讲接口

    接口

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

    开放闭关原则:

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

    参数传值机制
    静态初始化块
    static 关键字
    this关键字
    开发中容易造成内存泄露的操作
    通用的分代垃圾回收机制
    JVM调优和Full GC
  • 原文地址:https://www.cnblogs.com/chenyanbin/p/11020578.html
Copyright © 2011-2022 走看看