为何要用接口?好处在哪里?spa
若是你的工做是一个修水管的,一天客户找上你让你帮装水管,可是有个要求,就是客户喜欢管子是三角形的。设计
你立马买了三角形的水管回来,在墙上弄个三角形的口子,客户付了钱,你很开心今天有了收入,以下图,很好:code
可是好景不长,客户过了一个星期又来找,由于他以为三角形很差看,要让你换成正方形的水管,你不得不换,由于顾客就是上帝。好吧,继续在墙上弄个正方形的口子,而后又换成正方形的管子来接上。好了,以下图:(可是可能以为为何一开始不说要正方形的?由于需求总在变化。。。)blog
你累得满头大汗,可是仍是完成了。惋惜不久,客户又来找你,由于他想换成椭圆形的管子了。虽然你很无奈,可是你仍是不得不花了几个小时完成。以下图:继承
安装完成,这时你可能在考虑,为何换不一样形状的水管,我都要大动干戈一番呢?因而你想到一个好方法,那就是墙上设计一个固定的水管而且是圆形的,当客户喜欢什么形状的水管,那么我只须要把客户喜欢的水管的一头作成圆形的,这样,之后都不须要去动墙上的水管了。这是一个好办法。就先在墙上弄个圆形的口,这个口就叫作接口。以下图:接口
如你所见,墙上有个圆形的口,可是按照本来的:图片
三角形水管两端是三角形
正方形水管两端是正方形
椭圆形水管两端是椭圆形string
那是确定接不上的,由于三角形、正方形、椭圆形的口怎么和墙壁上圆形的口对接呢?it
因此先要实现接口,把:class
三角形水管一端作成圆形
正方形水管一端作成圆形
椭圆形水管一端作成圆形
如图因此,圆形接口作出来了,具体实现是客户去安装,接口自己并不会安装其余形状的水管,换句话说就是接口没有具体实现,只是告诉你,你的水管要接入,必须有一端是圆形的(接口的约束),由于我只留这个圆形的接口,你要装别的形状的管子,先把一个弄成圆形的就行了(子类去实现接口的方法),无论什么形状,都要一个必须作成圆形才能对接得上,它必需要你按照个人规范来作。这就是为何新手会以为接口什么都不作,只定义接口,没有任何实现,那不是画蛇添足吗?由于它的实现是子类去完成。这样只要客户喜欢什么形状的水管,只要实现了个人接口(圆形),都能对接得上,并且改变起来也很方便,只要把水管扭上去就好了,不用在去给墙壁挖洞了
下面咱们在代码里体现接口的做用,如下例子的场景不讨论是否合理,因为如下代码是在txt编写,不保证运行无误。
需求:公司有两我的分别写了2个动物类,让你写一个类来输出它们各自喜欢的食物。
//A写的Dog类,里面有个likeFood方法,以下: class Dog { public void likeFood() { Console.WriteLine("我是小狗,我喜欢吃肉"); } } //B写的Cat类,里面有个likeFood方法,以下: class Cat { public void likeFood() { Console.WriteLine("我是小猫,我喜欢吃鱼"); } }
你写的Zoo类以下:
//动物园类 class Zoo { public void show(Dog dog){ dog.likeFood(); } public void show(Cat cat){ cat.likeFood(); } }
在输出的时候使用以下:
public static void Main(string[] args) { Zoo zoo = new Zoo(); zoo.show(new Dog()); //"我是小狗,我喜欢吃肉" zoo.show(new Cat()); //"我是小猫,我喜欢吃鱼" }
这一切工做良好,但好景不长,公司又须要给动物园增长一个猴子,让C去写这个Monkey类,并能输出它喜欢的食物。
class Dog { public void likeFood() { Console.WriteLine("我是小狗,我喜欢吃肉"); } } //B写的Cat类,里面有个likeFood方法,以下: class Cat { public void likeFood() { Console.WriteLine("我是小猫,我喜欢吃鱼"); } } //C写的Monkey类,里面有个likeFood方法,以下: class Monkey { public void likeFood() { Console.WriteLine("我是猴子,我喜欢吃桃子"); } }
因而你的Zoo类就变成了这样,仅仅多了一个重载方法:
class Zoo { public void show(Dog dog) { dog.likeFood(); } public void show(Cat cat) { cat.likeFood(); } public void show(Monkey money) { money.likeFood(); } }
public static void Main(string[] args) { Zoo zoo = new Zoo(); zoo.show(new Dog()); //"我是小狗,我喜欢吃肉" zoo.show(new Cat()); //"我是小猫,我喜欢吃鱼" zoo.show(new Monkey()); //"我是猴子,我喜欢吃桃子" }
输出结果也良好,你不由暗暗得意,一个变化而已,我只须要再Zoo类里增长一个重载方法就行了。
但你仔细一想:“若是后面还有更多动物要输出它们喜欢的食物,个人Zoo类都要修改,这对我来讲不是一件好事。”
而后你再仔细观察Zoo类,发现不变的是show方法,变化的是show方法是参数。由于每一个动物都不同,因此参数也就不同。因此原来就须要重载多个方法。
若是有一个类,能接收全部动物,那不就解决了?没错,因而你想到了定义一个父类叫Animal,里面有个likeFood方法,让全部动物类去继承Animal。
最后你的Zoo类和Animal类代码以下:
class Zoo { public void show(Animal animal) { animal.likeFood(); } } class Animal { public void likeFood() { Console.WriteLine("我是Animal类"); } }
你告诉原来的A和B两人,让它们写的动物类都去继承Animal,而且里面有个输出动物喜欢食物的方法。
A、B、C写的类修改后以下:
class Dog : Animal { public void likeFood() { Console.WriteLine("我是小狗,我喜欢吃肉"); } } class Cat : Animal { public void likeFood() { Console.WriteLine("我是小猫,我喜欢吃鱼"); } } class Monkey : Animal { public void likeFood() { Console.WriteLine("我是猴子,我喜欢吃桃子"); } }
Zoo也须要修改,最后代码以下:
class Zoo { public void show(Animal animal) { animal.likeFood(); } } public static void Main(string[] args) { Zoo zoo = new Zoo(); zoo.show(new Dog()); //"我是小狗,我喜欢吃肉" zoo.show(new Cat()); //"我是小狗,我喜欢吃肉" zoo.show(new Monkey()); //"我是猴子,我喜欢吃桃子" }
运行也一切良好,无论你之后还有什么类,只要让须要添加的动物类,继承Animal,并有个likeFood方法,那么你无需修改Zoo,只须要再main方法里传入动物类的实例就能正常工做。
你大赞你聪明绝顶,这样一来,你的Zoo根本不须要改变了。
有一天,公司新来一我的,暂时叫D吧,公司让D写个兔子类,你告诉D,你写的Rabbit类必须继承Animal,而且有一个它喜欢的食物的方法,。
D写的兔子类以下:
class Rabbit : Animal { public void favoriteFood() { Console.WriteLine("我是兔子,我喜欢吃萝卜"); } }
public static void Main(string[] args) { Zoo zoo = new Zoo(); zoo.show(new Dog()); //"我是小狗,我喜欢吃肉" zoo.show(new Cat()); //"我是小猫,我喜欢吃鱼" zoo.show(new Monkey()); //"我是猴子,我喜欢吃桃子" zoo.show(new Rabbit()); //"我是Animal类" }
Raabit并无输出预想的结果,你不得不花了点时间去排查缘由,最后你发现这不是什么大问题,由于新来的D虽然写了Rabbit类,可是他并不知道大家以前约定的动物喜欢的食物命名为:likeFood()
D写的Rabbit类,里面的方法叫:favoriteFood()
虽然最后D修改他的Rabbit类的方法为likeFood(),但你仍是对这个问题作了一番思考,为何会致使这个问题?
那是由于没有一种约束,使得子类继承父类的时候必须实现父类的方法。有没有一个类,能让它的子类必须实现它定义的方法?有,那就是接口。
因而你修改Animal为接口,代码以下:
interface Animal { public void likeFood(); }
因为Animal接口有个likeFood()方法,那么Rabbit子类去实现Animal接口必须实现likeFood(),不然程序不能经过。
代码正常工做,由于Animal是接口,里面有个likeFood()方法,之后再添加各类动物进来,只须要实现Animal接口,而且也不会出现有的人会由于子类的方法命名问题而致使出错了。
这时你再想,虽然用继承一个普通父类也能够知足要求,可是一个普通父类根本没有约束力
而用了接口就不同了,子类必须实现父类的全部方法,由于Zoo类里调用的是likeFood(),因为子类必须实现父类,那么全部子类都会有likeFood(),你根本不用担忧子类有没有这个方法。
因此接口能在多人协做下,定义一系列方法,让子类必须存在接口定义的类,防止在另外的类里调用一我的写的接口的子类时,找不到方法的问题。
开放闭关原则: