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:

浙公网安备 33010602011771号