接口interface
在面向对象里抽象类说道,如果一个基类全部都抽象了。都没有具体的实现,和接口很像。
但意义上又不是接口。
接口的产生:
一个派生类对象可以看成是一个基类对象,也就是说一个派生类对象”是一个”基类对象。一只猫可以说是一只动物,看多态的概念。
- 接口是has-a的关系
接口更像是功能的集合,是一种约定的功能,但是没有具体实现。子类按照这种约定的功能实现接口。子类有这个功能(has)但是子类不是这个功能(is)
- 抽象类中的方法不能是private,其他都可以。
- 接口中的方法肯定是public的,因为是必须的,所以C#干脆禁止你写访问符
接口是什么?举例
猫,狗,鱼都是(is)动物,继承动物类。动物共有的特征,吃,睡,动等。猫狗鱼继承了动物,他们也都有吃睡动的特征。 但是猫,狗有(has)[掉毛]这种行为。动物基类没有,不是所有动物都有毛的。比如鱼。 现在写一个掉毛功能的接口,猫狗继承动物类,拥有动物类特征的同时,实现这个掉毛接口,有(has)了掉毛的行为。但猫狗不是(is)掉毛。
其实这种例子是结合现实逻辑来的。写项目往往很多类没有啥现实逻辑。写抽象类抽象方法完全就是基类的方法用不到,干脆不要方法体,写个抽象的,基类全部都抽象了,不如用接口代替算了。
往往软件工程无法和现实映射,但是也要做到面向对象开发,换句话说面向接口也可以。
接口简单实现
//家养动物的功能接口,一般接口用I开头interface IJiaYangChongWu{void DiaoMao();//约定一个掉毛功能}abstract public class Animal{public abstract void Sleep();public abstract void Eat();}public class Cat : Animal,IJiaYangChongWu{//实现接口不用overridepublic void DiaoMao(){Console.WriteLine("猫掉毛");}public override void Eat(){Console.WriteLine("猫吃鱼");}public override void Sleep(){Console.WriteLine("猫在猫窝里面睡觉");}}public class Dog : Animal,IJiaYangChongWu{public void DiaoMao(){Console.WriteLine("狗掉毛");}public override void Eat(){Console.WriteLine("狗吃肉");}public override void Sleep(){Console.WriteLine("狗在狗窝睡觉");}}public class Fish : Animal{public override void Eat(){Console.WriteLine("鱼吃东西");}public override void Sleep(){Console.WriteLine("鱼在水里睡觉");}}
接口隔离原则
实现类不应该依赖它不需要的接口,对接口的依赖应该建立在最小依赖的基础上。
一个接口A,他的实现类W会实现这个接口A的所有功能abcdefg,但是有些功能实现类W并不需要 实现类W只需要abcd功能,而接口A多出了efg功能。 解决办法就是:把接口A拆分成多个小接口,比如接口ABCDEFG,每个接口对应abcdefg功能。实现类W需要abcd功能,就实现ABCD接口,EFG接口不实现。 当另一个实现类需要cdef功能,就实现CDEF接口,其他接口不实现。 这些实现类就没有了他不需要的功能。
namespace ConsoleApp2{//交通工具接口interface IVehicle{void Run();}//武器接口interface IWeapon{void Fire();}//飞行接口interface IFly{void Fly();}//坦克接口,实现了交通工具的功能,还实现了武器的功能interface ITank:IVehicle,IWeapon{}//战斗机接口interface IFighter : IVehicle, IWeapon, IFly{}//汽车class Car : IVehicle{public void Run(){Console.WriteLine("汽车跑");}}//坦克class Tank : ITank{public void Fire(){Console.WriteLine("坦克开火");}public void Run(){Console.WriteLine("坦克跑");}}//战斗机class Fighter : IFighter{public void Fire(){Console.WriteLine("飞机开火");}public void Fly(){Console.WriteLine("飞机飞");}public void Run(){Console.WriteLine("飞机跑");}}//驾驶人class Person{//只要一个交通工具,不管是车,坦克还是飞机。IVehicle是这些的基接口private IVehicle vehicle;public Person(IVehicle vehicle){this.vehicle = vehicle;}public void Drive(){//我只需要跑的功能vehicle.Run();}public void Attack(){//如果要使用Fire,接口就不能是基接口IVehicle了,因为他没有,得是IWeapon//凡是继承了IWeapon接口的都能用}}}
namespace ConsoleApp2{class Program{static void Main(string[] args){Person p = new Person(new Car());p.Drive();//car能跑Person p2 = new Person(new Tank());p2.Drive();//坦克能跑,因为都继承了IVehicle基接口}}}
接口的显式实现
namespace ConsoleApp2{interface IA{void A();}interface IB{void B();}class C : IA, IB{public void B(){Console.WriteLine("BBBB");}//这是显式实现,调用C类的A方法时,必须把它当成IA类型的变量void IA.A(){Console.WriteLine("AAAA");}}}
namespace ConsoleApp2{class Program{static void Main(string[] args){C c = new C();c.B();//这时候只能调用BIA a = new C();a.A();//这时候可以调用A}}}
