【问题标题】:OO Design / Implementation in MVC 4MVC 4 中的 OO 设计/实现
【发布时间】:2013-10-02 22:07:30
【问题描述】:

我有一个 OO 设计/数据库问题。我正在使用实体框架 5 在 Microsoft MVC v4 中进行编码。 假设模型如下:

public class Car
{
  public int Id {get; set;}
  public string Name {get; set; }
  public int Wheels {get; set;}
}
public class Truck : Car
{
  public int CargoCapacity {get; set;}
}
public class Bus : Car
{
  public int PassangerCapacity {get; set;}
}

在稍后阶段,我可能想要扩展模型,因此必须考虑这一点。例如:添加具有“NumberOfTurbos”属性的赛车。

遵循良好的面向对象设计原则:

问题 1: 这些都应该在单独的类中还是与修饰符合二为一。 从面向对象的角度来看原则的分离,我会说将它们分开。此外,封闭/开放原则规定它们应该分开,这将有助于我稍后添加赛车,而不必更改任何关于公共汽车、卡车等的东西。

问题 2: 它们都应该在同一个数据库表中吗?尽管我不认为类的数量应该决定表的数量,但我仍然会选择单独的表,以便对数据库进行规范化并且到处都没有未使用的字段。默认情况下,代码优先将所有内容放在一个表中,但我已将其与类模式属性分开。

问题 3: 如果我应该对接口而不是具体类进行编程(再次是 OO 原则),这将如何工作,因为如果我有类似 ICar 的东西由具体类 car 实现,那么将内容转换为 ICar 将不起作用。像 List 这样的东西不会给我所有正确的数据。将 MVC 视图实现到接口 ICAR 也很困难。

我什至应该将接口放在仅属性类上吗?我应该在这里使用存储库之类的东西还是其他一些模式/想法?

对于这个冗长的问题,我深表歉意,感谢您的帮助。 提前致谢。 迈克

【问题讨论】:

  • 您应该使用更通用的东西,而不是使用“汽车”,例如“WheeledVehicle”既不是卡车也不是公共汽车。
  • 更不用说看到public class Motorcycle : Car会很奇怪
  • 是的,这是一个错误的命名选择,仅用于说明目的。

标签: c# asp.net-mvc oop database-design


【解决方案1】:

问题 1:这些都应该在单独的类中还是全部与修饰符合二为一。从面向对象的角度来看原则的分离,我会说将它们分开。此外,封闭/开放原则规定它们应该分开,这将有助于我稍后添加赛车,而不必更改任何关于公共汽车、卡车等的东西。

实际上是单独的类,每个项目类型一个类。这也将成为未来的证明,因为您对任何班级所做的任何更改都不一定会影响其他班级。将来要共享的任何添加内容都可以放在基类中。


问题 2:它们应该都在同一个数据库表中吗?尽管我不认为类的数量应该决定表的数量,但我仍然会选择单独的表,以便对数据库进行规范化并且到处都没有未使用的字段。默认情况下,代码优先将所有内容放在一个表中,但我已将其与类架构属性分开。

不,绝对不是。是的,查询会更容易,但您查询的数据量实际上会增加。另外,您正在有效地对数据库设计进行非规范化,更不用说加载大量可为空的字段,如果一种类型需要这些字段,而其他类型不需要这些字段,则可能会涉及一些丑陋的逻辑来验证。


问题 3:如果我应该对接口而不是具体类进行编程(再次是 OO 原则),这将如何工作,因为如果我有类似 ICar 的东西,它由具体类 car 实现,将东西转换为 ICar不管用。像 List 这样的东西不会给我所有正确的数据。将 MVC 视图实现到接口 ICAR 也很困难。

您不应该对接口进行编程,您应该选择完全依赖于实现的接口/基类。我想说在你的例子中,只使用一个基类(比如VehicleBase,你可以把所有的共享属性放在里面。

【讨论】:

  • 感谢您的回答,所以我们在#1 和#2 上基本上是一致的。请对#3进行更多说明。在这种情况下,带有编辑或列表脚手架的视图将如何工作。常见的车辆项目将首先显示,然后将是多个“如果是巴士类型,则显示巴士属性”,“如果是卡车类型,则显示卡车属性”,如果我会变得非常大和混乱添加更多车辆类型。有没有一种整洁/正确的方法来处理这个?谢谢
  • @MikeBryant 老实说,我不是脚手架的粉丝,我更喜欢自己做。从编辑的角度来看,我不会尝试在一个动作中处理所有事情,因为那会是一个混乱(尤其是随着事情的发展)。为了保持独立和面向未来,我会为每种类型设置一个编辑操作。
  • 所以你是说在我的车辆控制器中我会有一个 EditCar()、EditTruck()、EditBus() 和一个单独的视图?实际上,ViewCar()、ViewTruck()、ViewBus() 和每个编辑方法都有 2 个版本,一个用于加载,一个用于保存。是不是越来越乱了?
  • @MikeBryant 这并不理想,但它确实是两害相权取其轻。您的另一种选择是一个视图,基本上是一个关于车辆类型的switch 声明,然后是一个模型,它是所有车辆中所有字段的混搭。
  • 是的,如果/切换实体以尝试保留打开/关闭和 SOC,我想避免这种情况。我认为您为每种车辆类型添加动作和视图的想法可能会更好。我什至可以尝试将动作抽象为某种类。谢谢。
【解决方案2】:
  1. 是的,它们应该属于不同的类别。模型中的实体不应具有逻辑上不“属于”它们的属性。在处理Truck 时,设置或读取PassangerCapacity 很可能没有意义。那只会令人困惑。

  2. 这是在 ORM 层(在您的情况下为 EF)中做出的选择。 EF 支持包含所有子类的属性列的单个表,以及子类的多个表。这两种选择都有其优点。单个表的连接较少,因此可能更快,但多个表减少了数据库必须存储、读取和写入的列数,因此在存储方面它可能更有效。这一切也取决于实际数据集的样子。然而,这将被 ORM 层 (EF) 抽象出来,因此在您的对象模型中它们仍然应该是分开的。

  3. 如果你的代码需要处理卡车,你应该让它处理卡车,对于只关心汽车的地方,使用ICar。您的数据库层可以公开包含汽车、卡车和赛车的数据集。

【讨论】:

    【解决方案3】:

    答案 1:

    是的,这些应该分成多个类。您可以通过将Car 标记为抽象来进一步扩展它,因为它是其他类型汽车的基类。您还必须将属性标记为抽象,如下所示:

    abstract class Car
    {
        abstract public int Id;
    }
    

    虽然更好的名称可能是Vehicle

    答案 2:

    您可以将这些存储在一个名为 Vehicle 的表中,并拥有一个 VehicleType 表。

    桌车:

    Id VehicleName VehicleType

    1 丰田 1

    2 川崎 2

    表格车辆类型:

    ID 车辆描述

    1 辆车

    2 摩托车

    3 辆卡车

    答案 3:

    如果您使用了一个接口并且有一个列表,那么您将受限于ICar 接口公开的属性/字段。但是,您可以将其转换为适当的 VehicleType。

    【讨论】:

    • LOOOOOOOOOOOOOOOOL 有多少机会,我是说真的?
    • 又在 iPhone 上编程? Pr0 ;)
    • @mattytommo - 现在有 20MB 宽带 ;) - 睡觉了。早上见,参加一些 SO 声誉比赛 XX ~~
    • 不错,晚安!如果你的宽带线被切断了肯定不是我;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多