处理ASP.NET MVC中的子类型

时间:2010-02-21 01:12:07

标签: asp.net-mvc polymorphism

我无法想到处理以下情况的“最佳”方式 - 基本上,我有一堆存储对象从基类型继承并希望能够从存储中检索一个,找到它的子类型(也许通过“if(x是y)”)然后相应地采取行动 - 一些使用共享实现,另一些使用专用逻辑和视图。

我猜[剥离]这看起来有点像:

/vehicle/details/1234

- Views
  - Vehicle
    - Details.aspx

abstract class Vehicle{
  public int ID{ get; }
}
class Motorbike : Vehicle{
  //whatever  
}
class Car : Vehicle{
  public int NoOfDoors{ get; }
}

class VehicleController : Controller{
  VehicleRepository _vehicleRepository; //injected, etc
  public ActionResult Details(int id){
    var vehicle = _vehicleRepository.Get(id);
    //we can now figure out what subtype the vehicle is
    //and can respond accordingly
  }
}

现在,如果我们不担心未来的扩展和维护以及所有这些,我们可以沿着黑暗的道路走下去并实施类似下面的东西 - 这将起到很好的作用,但毫无疑问会成为绝对的梦魇。

- Views
  - Vehicle
    - Details.aspx
    - CarDetails.aspx

public ActionResult Details(int id){
  var vehicle = _vehicleRepository.Get(id);
  return (vehicle is Car) ? DetailsView((Car)vehicle) : DetailsView(vehicle);
}
private ActionResult DetailsView(Car car){
  var crashTestResults = GetCrashTestResults(car);
  var carData = new CarDetailsViewData(car, crashTestResults);
  return View("CarDetails", carData);
}
private ActionResult DetailsView(Vehicle vehicle){
  var vehicleData = new VehicleDetailsViewData(car, crashTestResults);
  return View("Details", vehicleData);
}

另一种机制是在视图层使用子文件夹 - 这将保持代码合理清洁,但不适用于我的情况,因为我也想要一个自定义操作方法......

- Views
  - Vehicle
    - Car
      - Details.aspx
    - Motorbike
      - Details.aspx

public ActionResult Details(int id){
  var vehicle = _vehicleRepository.Get(id);
  return View(vehicle.GetType().Name + "\Details", vehicle);
}

理想情况下,解决方案将是一个基本控制器和专用控制器,并在需要时覆盖 - 但由于我们必须先从存储中拉出对象才能确定理想的控制器,否则我无法弄清楚如何使其工作。 ..

我目前的想法通常落在第一个障碍,让“VehicleController”对这些子类型覆盖的内容了解得太多,所以任何想法都会受到赞赏。

干杯。

3 个答案:

答案 0 :(得分:0)

我可以看到两种解决方案,具体取决于哪种解决方案可以减少重复:

1)让Vehicle包含抽象方法GetViewNameGetViewData,它允许您拥有多个视图,但您的控制器不需要了解它们。

2)让Vehicle包含一个抽象的GetViewData方法,该方法返回一个包含该类的所有ViewData的对象。然后ViewData将实现接口,您的单个视图可以基于if (ViewData is IHasCrashTestData)或类似的东西来调整HTML部分。

在大多数情况下,我建议选项1更具可扩展性。

答案 1 :(得分:0)

我可能错了,但它真的让我觉得你只是想问一下如何渲染适合给定子类型的视图(例如摩托车或船或其他)。

除了不同的视图内容之外,控制器逻辑看起来并不像每种车型都需要不同。您是否真的试图根据车辆类型更改程序流程,还是控制器主要是关于处理CRUD操作?

假设您只是尝试更改渲染视图,那么请查看MVC 2的DisplayFor和EditorFor功能。这应该允许你传递模型类型,然后渲染一个合适的视图(iirc,没有玩过多)。

如果这不是你想要的方式,或者如果你不想使用MVC 2,因为它只是RC,而不是RTM,那么你的下一个最好的选择是覆盖ViewEngine(可能是你的当前子类)一)改变查看视图的逻辑,以涵盖上面基于文件夹的场景或你想要应用的任何方案。

答案 2 :(得分:-1)

为什么要为所有类型的车辆创建新的控制器。在数据库中,N-M关联将是简单而灵活的。

VehicleTypes
    ->Id
    ->Name

VehicleTypeVariables
    ->Id
    ->Name

Vehicles
    ->Id
    ->VehicleTypeId

VehicleVariables
    ->Id
    ->VehicleId
    ->VehicleTypeVariableId
    ->Value