1.接口隔离原则
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
怎么样去理解上面这段话呢,我们设想一种情景,如果有一位全能司机,他既会开汽车又会开坦克,那么以下面这段代码为例,如果这个时候我们想让司机去驾驶坦克,那必然需要修改Driver类 将Ivehicle接口类型的字段更改为ITank接口类型的字段,当我们的司机驾驶不同类型的载具时,我们反复去修改Driver类,这显然违反了我们的开闭原则。
class Driver
{
private Ivehicle vehicle;
public Driver(Ivehicle _vehicle)
{
this.vehicle = _vehicle;
}
public void Drive()
{
vehicle.Run();
}
}
interface Ivehicle //车辆接口
{
void Run();
}
class Car:Ivehicle
{
public void Run()
{
Console.WriteLine("Car is Running");
}
}
interface ITank //坦克接口
{
void fire();
void Run();
}
class LightTank : ITank
{
public void fire()
{
Console.WriteLine("30mm");
}
public void Run()
{
Console.WriteLine("Light tank 90km/h");
}
}
在现在的情景当中,我们的司机只与车辆的run方法相关(司机只需要开车) ,那对于我们的Driver类来说,传进来的ITank接口就太大了(接口太胖了,存在不会去使用的方法),这样的设计就违反了我们的接口隔离原则,对于ITank接口来说,它内部的run方法和fire方法其实该分别属于车辆和武器。那我们这样来改动我们的代码。
interface Ivehicle
{
void Run();
}
interface IWeapeon
{
void fire();
}
interface ITank : Ivehicle, IWeapeon { }
我们将我们的ITank接口拆分为由两个小接口组成的一个接口。这样当我们的司机去驾驶LightTank时只需要传一个Ivehicle类型的字段即可。这样的设计也就符合了我们开头所说的:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
static void Main(string[] args)
{
LightTank mytank = new LightTank();
Driver me=new Driver(mytank);
me.Drive();
Console.ReadLine();
}
class Driver
{
private Ivehicle vehicle;
public Driver(Ivehicle _vehicle)
{
this.vehicle = _vehicle;
}
public void Drive()
{
vehicle.Run();
}
}
需要注意的是,由于我们向Driver类中传递的是ITank接口的父接口Ivehicle类型的字段的参数,那对于我们来说我们也只能访问到汽车的Run方法,是不能访问到IWeapeon接口中的fire方法的(如果不理解这里,那就需要补充C#多态方面的知识)。这样对于现在的实际情况来看,我们的Driver类中拿到的接口就不会是一个胖接口(大接口,其中有用不到的功能,就像最开始将Itank接口类型的字段替换掉Ivehicle接口类型的字段一样)。
这是我对B站Up主TimothyLiu(刘铁猛老师!!!)对于接口隔离的学习与总结,如有错漏,恳请指出!谢谢!