c#基础-接口

Why&For What?

 

为什么要用接口?接口好处在哪?

  如果你是一个管道工人(当然不是超级玛丽),有一天,有个客户让你帮忙装一个水管,一个三角形的水管。没错,就是三角形的,别管为什么,客户就是想要。

  

  于是,你撸起袖子加油干,哼哧哼哧地干完了。

 

  故事并没有结束,一个月后,客户提出了新的需求,我老婆说三角形的不行,要正方形的。

 

  好吧,顾客是上帝,得罪谁也不能得罪上帝,上帝的老婆更是万万不能得罪的。你又哼哧哼哧地干完了,但是你有预感,这单子并没有那么简单。

 

  果然,又过了一个月,客户又提出了新的需求,最近我走霉运,我请了一个风水先生来我家看风水,风水先生说这个排水口要椭圆形才能让我去掉霉运。

 

  你不得不哼哧哼哧地把管子换成椭圆形的。在经历了人生的“大起大落”之后,你不由地陷入深深的思考,超市的方便面屡遭黑手,老尼姑的门夜夜被敲究竟是人是鬼,这一切的背后!!是人性的扭曲还是道德……不对,客户的需求一再更改,水管的形状千变万化,这到底是偶然还是必然。最终你得到了一个答案,需求的变更是必然的。于是你开动脑子想出了一个解决方案:墙上设计一个固定的水管并且是圆形的,当客户喜欢什么形状的水管,那么我只需要把客户喜欢的水管的一头做成圆形的,这样,以后都不需要去动墙上的水管了。哼~我命由我不由天,风水先生告诉你换什么,我就能给你换上!

 

  如图所以,圆形接口做出来了,具体实现是客户去安装,接口本身并不会安装其他形状的水管,换句话说就是接口没有具体实现,只是告诉你,你的水管要接入,必须有一端是圆形的(接口的约束),因为我只留这个圆形的接口,你要装别的形状的管子,先把一个弄成圆形的就好了(子类去实现接口的方法),不管什么形状,都要一个必须做成圆形才能对接得上,它必须要你按照我的规范来做。这样只要客户喜欢什么形状的水管,只要实现了我的接口(圆形),都能对接得上,而且改变起来也很方便,只要把水管扭上去就行了,不用再去给墙壁挖洞了。

Use it

  现在你已经是一个程序员了(不再是超级玛丽了),你的同事写了两个动物类,一个是Tiger,一个是Monkey,想要让你写一个Zoo类来实现它们的Eat方法。

    public class Monkey
    {
        public void Eat()
        {
            Console.WriteLine("我是猴赛雷,我喜欢吃大香蕉");
        }
    }
    public class Tiger
    {
        public void Eat()
        {
            Console.WriteLine("社会你虎哥,吃肉话不多");
        }
    }

  于是你写了一个Zoo类来使用它们的方法。

    public class Zoo
    {
        public void Show(Monkey monkey)
        {
            monkey.Eat();
        }

        public void Show(Tiger tiger)
        {
            tiger.Eat();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Zoo zoo = new Zoo();
            zoo.Show(new Monkey());
            zoo.Show(new Tiger());
            Console.ReadKey();
        }
    }

一周后,又有一个同事写了一个Bear类,希望也能让你实现它的Eat方法。

    public class Bear
    {
        public void Eat()
        {
            Console.WriteLine("我是熊孩子,我很皮,我要吃蜂蜜");
        }
    }

你心里冷笑一声,a piece of cake!不过是多一个重载方法而已。

    public class Zoo
    {
        public void Show(Monkey monkey)
        {
            monkey.Eat();
        }

        public void Show(Tiger tiger)
        {
            tiger.Eat();
        }

        public void Show(Bear bear)
        {
            bear.Eat();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Zoo zoo = new Zoo();
            zoo.Show(new Monkey());
            zoo.Show(new Tiger());
            zoo.Show(new Bear());
            Console.ReadKey();
        }
    }

运行结果良好,你心中不禁暗自得意,我真是个天才。这时候,又一个同事过来,他写了一个Wolf类,希望……“我真傻,真的,”你心里这样说,“我单知道Zoo的重载方法能实现动物类;我不知道动物类会一个接一个来。” 于是你痛定思痛,仔细观察了一下Zoo类,发现不变的是Show方法,变的是传给Show方法的参数。你定义了一个Animal作为父类,让动物类都去继承它。

    public class Animal
    {
        public virtual void Eat()
        {
            Console.Write("我要吃东西");
        }
    }
    public class Monkey : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("我是猴赛雷,我喜欢吃大香蕉");
        }
    }

    public class Tiger : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("社会你虎哥,吃肉话不多");
        }
    }

    public class Bear : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("我是熊孩子,我很皮,我要吃蜂蜜");
        }
    }

    public class Wolf:Animal
    {
        public  override void Eat()
        {
            Console.WriteLine("我是灰太狼,我今天就要吃喜羊羊,谁说话都不好使");
        }
    }
    public class Zoo
    {
        public void Show(Animal animal)
        {
            animal.Eat();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Zoo zoo = new Zoo();
            zoo.Show(new Monkey());
            zoo.Show(new Tiger());
            zoo.Show(new Bear());
            zoo.Show(new Wolf());
            Console.ReadKey();
        }
    }

OK!这样就万事大吉了。一切都很理想。一个月之后,来了一个新同事。新同事要写一个Goat类,你告诉他,只要继承了Animal类,再定义一个方法来显示Goat喜欢吃的东西就好了。然而,在整合的时候,Goat并没有输出想要的结果,作为关键人物,你只能留下来加班来找bug。你终于发现了bug,原来新同事的Goat类的方法名字不一样。

    public class Goat:Animal
    {
        public override void EatFood()
        {
            Console.Write("别看我只是一只羊,绿草因为我变得更香");
        }
    }

这时,你心中又浮现那段话,“我真傻,真的,我单知道……”。最后D修改他的Goat类的方法为Eat(),但你还是对这个问题做了一番思考,为什么会导致这个问题?
那是因为没有一种约束,使得子类继承父类的时候必须实现父类的方法。有没有一个类,能让它的子类必须实现它定义的方法?有,那就是接口。于是,最终版的动物园出炉了。

    public interface Animal
    {
        void Eat();//访问修饰符public已经在接口声明,不需要再在方法中声明
    }

 

    public class Bear : Animal
    {
        public void Eat()
        {
            Console.WriteLine("我是熊孩子,我很皮,我要吃蜂蜜");
        }
    }

    public class Tiger : Animal
    {
        public void Eat()
        {
            Console.WriteLine("社会你虎哥,吃肉话不多");
        }
    }

    public class Monkey : Animal
    {
        public void Eat()
        {
            Console.WriteLine("我是猴赛雷,我喜欢吃大香蕉");
        }
    }

    public class Wolf:Animal
    {
        public void Eat()
        {
            Console.WriteLine("我是灰太狼,我今天就要吃喜羊羊,谁说话都不好使");
        }
    }

    public class Goat:Animal
    {
        public void Eat()
        {
            Console.Write("别看我只是一只羊,绿草因为我变得更香");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Zoo zoo = new Zoo();
            zoo.Show(new Monkey());
            zoo.Show(new Tiger());
            zoo.Show(new Bear());
            zoo.Show(new Wolf());
            zoo.Show(new Goat());
            Console.ReadKey();
        }
    }

  代码正常工作,因为Animal是接口,里面有个likeFood()方法,以后再添加各种动物进来,只需要实现Animal接口,并且也不会出现有的人会因为子类的方法命名问题而导致出错了。
  这时你再想,虽然用继承一个普通父类也可以满足要求,但是一个普通父类根本没有约束力,而用了接口就不一样了,子类必须实现父类的所有方法,因为Zoo类里调用的是likeFood(),由于子类必须实现父类,那么所有子类都会有likeFood(),你根本不用担心子类有没有这个方法。所以接口能在多人协作下,定义一系列方法,让子类必须存在接口定义的类,防止在另外的类里调用一个人写的接口的子类时,找不到方法的问题。

 

 

Reference

  https://www.cnblogs.com/hamburger/p/4681681.html

posted @ 2018-01-02 17:42  Ja30n  阅读(248)  评论(0)    收藏  举报