gpt4 book ai didi

model-view-controller - 存储库模式 : What is the 'right size' ?

转载 作者:行者123 更新时间:2023-12-03 22:16:00 24 4
gpt4 key购买 nike

我正在为 MVC 应用程序构建一些存储库,并且我正在尝试提出在存储库之间划分职责的正确方法。在大多数情况下,这是显而易见的。但是有一种特殊情况,我不确定正确的答案是什么。

此应用程序的用户需要为其员工跟踪多种类型的时间。为简单起见,我们只考虑两个。我称它们为“考勤卡”和“考勤”。这两者之间差异的确切性质并不重要,但您应该注意最终用户将它们视为完全独立的数据。不过,我认为,他们认为它们完全独立的数据的原因是他们过去从未真正有机会看到它们在一起。两种类型的记录在编辑记录方面具有几乎完全不同的业务规则,但一般来说,它们也是员工在特定时间所处位置的两种记录。这两种类型的时间记录有很多共同的属性,例如总小时数,以及为其收集时间的员工。这两种类型还具有一些完全独特的单个类型的属性。我们将这些“额外”属性保存在另一种类型的实例中。所以一般的结构是这样的:

class TimeRecord 
{
Person Employee { get; set; }
TimeSpan? Hours { get; set; }
}

class TimeCardData
{
TimeRecord Record { get; set; }
TProperty TimeCardProperty { get; set; }
}

class AttendanceData
{
TimeRecord Record { get; set; }
TProperty AttendanceProperty { get; set; }
}

所以问题是, 这里需要多少个存储库?

1 个存储库

只有一个存储库的设计将公开返回“时间卡”、“出勤”记录或在一个列表中返回两种类型的方法。这对于存储库的客户来说相当方便,但在我看来,它有成为一个非常胖的类的真正危险。我认为仅“考勤卡”的存储库已经成为系统中最大的存储库之一,即使由于涉及复杂的业务规则而无需处理“出勤”。

2 存储库

另一种设计将有一个“考勤卡”存储库和另一个“考勤”记录存储库。这样做的好处是,例如“时间卡”的业务规则本身就在一个地方。但我也想有一种方法来获取所有时间记录的列表,无论类型如何。目前尚不清楚在这种情况下使用哪个存储库。两个都?

3 存储库

具有一个用于“时间卡”的存储库、另一个用于“出勤”记录的存储库以及提供所有时间记录的只读列表的第三个存储库的设计也是可能的。与 2 存储库设计一样,这具有优势,例如“时间卡”的业务规则本身就在一个地方。现在很清楚从何处获取组合列表。但是我发现我可以从两个不同的存储库中获得相同的记录有点奇怪。

杂交种

混合方法将使用单个存储库,但将任何业务规则代码(包括记录选择)移动到单独的类型中。在此示例中,单个“时间记录存储库”将聚合“时间卡”和“出勤”时间的业务规则实现类的实例。我认为这是我现在喜欢的方法。

其他?

我错过了什么?一种设计优于另一种设计有什么令人信服的论据吗?

最佳答案

  • 至少据我所知,存储库不是存放业务规则的地方。它们只是模仿系列的外观;在它们之下,它们基本上是纯数据访问(如果这是它们的工作,那么您可能也不会使用存储库来持久化任何东西)。因此,出于“业务规则”的原因,不应考虑使用单独的存储库。
  • 如果您的域对象确实是单独的对象,那么您应该有单独的存储库。记住什么是存储库:它是一个门面。它模仿您的域的集合。有关存储库的非常好的博客文章,请参见此处:http://devlicio.us/blogs/casey/archive/2009/02/20/ddd-the-repository-pattern.aspx

  • 存储库是一个门面;一个抽象。

    也就是说......我不认为你有单独的对象。您在这里遇到了一些与存储库无关的问题,而与域和域的设计有关。这两种“时间卡”实际上是两种不同的东西,还是真的相同?

    你说,“但是我发现我可以从两个不同的存储库中获得相同的记录有点奇怪。”

    这告诉我,它们实际上是相同的数据,以不同的方式表达。有办法处理这个问题。

    如果情况确实如此,那么您在这里拥有的是公共(public)基类的子类(例如,可以很容易地在 DB 中建模并使用 NHibernate 优雅地处理的东西)。

    我会给你一个我正在做的项目的例子。我有一个叫做“广播”的东西。这是一个基类;抽象的。无法实例化。我有这个类的两个特定的具体类型:DeviceBroadcast 和 FileBroadcast。一个从设备(如 DirectX 采集卡)流式传输音频/视频,一个从文件源(如 .mp3)流式传输音频/视频。

    我有一个返回广播对象的存储库。我可以将其转换为 FileBroadcast 以操作有关 FileBroadcast 的特定信息,或者出于同样的原因,我可以将其转换为 DeviceBroadcast - 如果它属于该类型。广播不能同时是 FileBroadcast 和 DeviceBroadcast 类型。它必须是其中之一。

    在数据库中,我将通用广播参数存储在广播表中,然后将文件特定属性存储在 FileBroadcast 表中。 DeviceBroadcast 表也是如此;分离。但是,当我通过存储库查询时,我只想要广播。那是我的根聚合对象,因此那是我的存储库。

    Broadcast 基类具有两个子类都使用的通用方法(例如 GetCommand() 方法,该方法返回特定的命令行参数以启动 VLC 进程)。子类必须重写并实现该方法,因为它是抽象的。这样,FileBroadcast 特有的“业务逻辑”就包含在 FileBroadcast 类中了。 DeviceBroadcast 特有的“业务逻辑”包含在 DeviceBroadcast 类中。两者共有的任何逻辑都包含在父类(super class) Broadcast 中。

    您似乎在这里有类似的情况,这就是我分享我的设计的原因。我想它可能对你有好处。

    最重要的是,请考虑您的域和数据。如果您打算通过单独的存储库获取重复数据,那么您需要更多地考虑如何设计域。也不要让用户决定您的域设计。他们从自己的角度了解领域。您所要做的就是能够以他们理解的方式向他们展示数据。这并不意味着你必须有一个糟糕的设计。您可以在幕后进行良好的设计,因为您的代码是必须使用域的东西。

    关于model-view-controller - 存储库模式 : What is the 'right size' ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/582289/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com