接口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
{
//实现接口不用override
public 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();//这时候只能调用B
IA a = new C();
a.A();//这时候可以调用A
}
}
}