【发布时间】:2017-10-30 17:12:11
【问题描述】:
我已经实现了一个 Vehicle 服务,负责维修汽车和卡车等车辆:
public interface IVehicleService
{
void ServiceVehicle(Vehicle vehicle);
}
public class CarService : IVehicleService
{
void ServiceVehicle(Vehicle vehicle)
{
if (!(vehicle is Car))
throw new Exception("This service only services cars")
//logic to service the car goes here
}
}
我还有一个车辆服务工厂,负责根据传入工厂方法的车辆类型创建车辆服务:
public class VehicleServiceFactory
{
public IVehicleService GetVehicleService(Vehicle vehicle)
{
if (vehicle is Car)
{
return new CarService();
}
if (vehicle is Truck)
{
return new TruckService();
}
throw new NotSupportedException("Vehicle not supported");
}
}
我遇到的问题是 CarService.ServiceVehicle 方法。它接受Vehicle,而理想情况下它应该接受Car,因为它知道它只会为汽车提供服务。所以我决定更新这个实现来使用泛型:
public interface IVehicleService<T> where T : Vehicle
{
void ServiceVehicle(T vehicle);
}
public class CarService : IVehicleService<Car>
{
void ServiceVehicle(Car vehicle)
{
//this is better as we no longer need to check if vehicle is a car
//logic to service the car goes here
}
}
public class VehicleServiceFactory
{
public IVehicleService<T> GetVehicleService<T>(T vehicle) where T : Vehicle
{
if (vehicle is Car)
{
return new CarService() as IVehicleService<T>;
}
if (vehicle is Truck)
{
return new TruckService() as IVehicleService<T>;
}
throw new NotSupportedException("Vehicle not supported");
}
}
我目前遇到的问题是调用这个工厂时如下:
var factory = new VehicleServiceFactory();
Vehicle vehicle = GetVehicle();
var vehicleService = factory.GetVehicleService(vehicle); // this returns null!
vehicleService.ServiceVehicle(vehicle);
GetVehicleService 返回null,我猜是因为我将基本类型Vehicle 传递到此方法中,所以T 将评估为Vehicle,并且无法从@987654333 转换@(实现IVehicleService<Car>)到有效的返回类型,即IVehicleService<Vehicle>(如果我错了,请纠正我)。
不胜感激有关如何解决此问题的指导。
【问题讨论】:
-
@oerkelens 它为空,因为
T是Vechicle,所以转换为IVehicleService<Vechicle>失败并返回null。 -
为什么要转换为 IVehicleService
?如果您从退货声明中删除 as IVehcileService<T>会发生什么? @juharr所以我后来注意到了,因此我删除了我的评论。问题仍然存在,GetVehicle()返回什么? -
现在的问题是你没有一个公共类型可以同时转换
CarService和TruckService,这是有充分理由的。简单地说IVehicleService<Car>不是IVehicleService<Vehicle> -
呃,我在这里遇到了严重的 SRP 头痛!你试图把太多的责任塞进一个单一的、糟糕的工厂班级。实际上,您应该有一个外观工厂类,它充当各个工厂的流量控制器,为您提供所需的特定类。 (……深深叹了口气,然后喝了一杯)。
-
插入一个我在进行代码审查时的常见抱怨:你不应该在没有检查结果的情况下使用
as。这样做会导致神秘的空引用异常,就像这样。如果您的意思是说“这东西确实属于这种类型”,那么只需转换它 - 至少当它失败时,您会在它发生的确切位置得到一个无效的转换异常,而不是在不同的位置难以调试空引用异常。
标签: c# generics interface factory-method