刘铁猛老师之所以把他们三个放在一起讨论,是因为他们都是基于反射机制的。而放在接口后面讲解,是因为反射大多数是配合接口一起使用的。
一个重要的概念——接口隔离原则:
契约,就是两个事。甲方说我不会多要(软性的规定,所以是设计方面的问题),乙方则说我不会少给(硬性的规定)
所以,判断甲方有没有多要,就看传给调用者的接口类型里,有没有一直没被调用到的函数成员。这就说明接口太大了。其中有两种具体原因
1. 接口太大,把太多的功能包含在里面了。违反了单一职责原则
一个类,应该只做一组相关的事。
解决方案:把大接口拆分为两个或者更多的小接口:
一个人,可以在公路上开车和坦克。但是车只有Run的功能,坦克有Fire和Run的功能。但是这个人只需要Run的功能。这就是接口过大,违反了接口隔离原则。而且在定义Driver类的时候,因为用的接口不同,导致他一次只能开一种。
class Program
{
static void Main(string[] args)
{
var driver = new Driver(new Car());//这里调用的实例也得改
driver.Drive();
}
}
class Driver
{
private IVehicle _vehicle;
//如果想开坦克了,就得把这里使用的接口换成Itank,下面的也都得换,特别麻烦。
//并且,在driver开车的时候,只会用到Run,而不会用到Fire
public Driver(IVehicle vehicle)
{
_vehicle = vehicle;
}
public void Drive()
{
_vehicle.Run();
}
}
interface IVehicle
{
void Run();
}
class Car:IVehicle
{
public void Run()
{
Console.WriteLine("Car is running......");
}
}
class Truck : IVehicle
{
public void Run()
{
Console.WriteLine("Truck is running......");
}
}
interface ITank
{
void Fire();
void Run();
}
class LightTank:ITank
{
public void Fire()
{
Console.WriteLine("Boom!");
}
public void Run()
{
Console.WriteLine("Tank is running...");
}
}
class HeavyTank : ITank
{
public void Fire()
{
Console.WriteLine("Boom!!!");
}
public void Run()
{
Console.WriteLine("ka ka ka ");
}
}
那应该如何改进呢?
就需要把ITank接口里的两个方法拆开成两个小的接口,但是也不太能太过于细致,使接口过于细碎。
(在C#里,类和类之间继承,只能有一个基类。接口,是可以有多个基接口)
interface Iweapon
{
void Fire();
}
interface ITank:Iweapon,IVehicle
{
}
在这里我把ITank这个接口拆成了两个接口,就可以实现不动上面Driver里面的代码,也可以通过调用Tank实例达到开坦克的行为。
static void Main(st