ASP.NET MVC:这个业务逻辑应该在哪里?

时间:2010-10-01 21:43:09

标签: c# asp.net-mvc oop

我正在研究我的第一个真正的MVC应用程序,并且我正在尝试遵循一般的OOP最佳实践。我正在重构我在控制器中使用的一些简单的业务逻辑到我的域模型中。我最近一直在做一些阅读,似乎很清楚我应该将逻辑放在域模型实体类中的某个地方,以避免“贫血域模型”反模式。

该应用程序将允许人们购买停车位的租约。价格取决于现场的长度以及客户是否是商业园区的成员。

所以我的域模型中的实体类看起来像这样(简化):

public class Customer
{
    int ID { get; set; }
    string Name { get; set; }
    bool IsMember { get; set; }
}

public class ParkingSpace
{
    int ID { get; set; }
    int Length { get; set; }
}

public class ParkingSpaceLease
{
    int ID { get; set; }
    DateTime OpenDate { get; set; }
    DateTime CloseDate { get; set; }
    Customer Customer { get; set; }
    ParkingSpace ParkingSpace { get; set; } 
}

编辑:只是为了澄清LeaseQuote不是实体类,因为它仅用于向透视客户显示成本细分,并且不会在任何地方持久存在。

public class LeaseQuote
{
    int SubTotal { get; set; }
    int Discount { get; set; }
    int Total { get; set; }
}

现在作为应用程序的一项功能,我需要能够为不同的客户和停车位组合生成报价。报价通常会在实际创建租约的情况下访问,例如当客户打电话询问价格时。

那么最好的方法是什么?是否有必要在控制器 中实例化一个新的ParkingSpaceLease对象来调用它上面的GetQuote方法?

var lease = new ParkingSpaceLease();
var quote = lease.GetQuote(length: 168, isMember: true);
return Json(quote);

或者LeaseQuote类应该有方法吗?

var leaseQuote = new LeaseQuote();
var quote = leaseQuote.GetQuote(length: 168, isMember: true);
return Json(quote);

将逻辑放在实际的ParkingSpaceLease类中感觉很奇怪。当我知道除了访问类似于单独服务的GetQuote方法之外我不打算对它做任何事情时,我觉得创建一个新的租约对象感觉有点“沉重”。

那么GetQuote方法应该去哪里?它为什么要去那里?

3 个答案:

答案 0 :(得分:4)

听起来你的LeaseQuote不是一个实体而是更多的商业级别。我的意思是,你不是把它存放在数据库的任何地方,是吗?它不是另一个数据对象的一部分。

当我看到这个

  

现在作为应用程序的一项功能,我需要能够为不同的客户和停车位组合生成报价。报价通常会在实际创建租约的情况下访问,例如当客户打电话询问价格时。

我想到了像这样的方法签名

public LeaseQuote GetQuote(Customer customer, ParkingSpace parkingSpace, int length)

但考虑到这一点,我可能还想在ParkingSpace实体中存储有关停车位成本的信息,并在Customer实体中存储(如果适用)客户折扣的信息。

这些东西会去哪里?在模型类(业务模型,而不是LINQ或实体模型)中访问您的实体并充当控制器的提供者。

现在我知道并没有完全按照书面形式使用你的模型。它可能只是个人偏见。但是当我考虑数据模型和数据实体时,除了从数据库返回的内容之外,它们不应该有任何插件方法。它们应该只是表示数据库中出现的未更改的数据。如果您对数据采取行动,则属于数据实体上方的层。

更新

  

我对您的示例感到好奇的是为什么人们想要传递完整的实体对象(客户和停车位)而不仅仅是执行计算所需的属性?

这取决于您的代码标准。如果消费代码操纵实体,则暴露实体本身可能是危险的。我更喜欢传递实体主要是因为这是我习惯的。但是我也小心不要在路上操纵实体。那,我认为方法签名反映了GetQuote方法关注的内容;它与客户和停车位有关。

我还可以证明,如果稍后有更多字段进入Entity会影响GetQuote方法,则方法签名不必更改。在这种情况下,只需要更改GetQuote的实现。

简答:偏好。

答案 1 :(得分:0)

只需在GetSpaceLease中将GetQuote设为静态方法。

答案 2 :(得分:0)

我认为你的对象模型可能略有歪斜,这会导致你担心租约是错误的地方,可以从中得到报价。在我看来,租约将完全由租赁的停车位组成,并且仅与购买租赁的客户有关。 IOW:

public class ParkingSpace
{
    int ID { get; set; }
    int Length { get; set; }
    IEnumerable<ParkingSpaceLease> Leases { get; set; }
    LeaseQuote GetQuote(Customer customer/*, other relevant parameters */) { ... }
}

public class ParkingSpaceLease
{
    int ID { get; set; }
    DateTime OpenDate { get; set; }
    DateTime CloseDate { get; set; }
    Customer Customer { get; set; }
}

public class LeaseQuote
{
    //Properties
    ParkingSpaceLease GetLease();
}

编辑我错过了关于LeaseQuote是一个单独课程的部分。