Model view controller 存储库模式:什么是';合适的尺寸';?

Model view controller 存储库模式:什么是';合适的尺寸';?,model-view-controller,domain-driven-design,repository-pattern,Model View Controller,Domain Driven Design,Repository Pattern,我正在为一个MVC应用程序构建一些存储库,并试图找到一种正确的方法来划分存储库之间的职责。在大多数情况下,这是显而易见的。但是有一个特别的例子,我不确定正确的答案是什么 此应用程序的用户需要跟踪其员工的多种时间类型。为了简单起见,我们只考虑两个。我将称之为“时间卡”和“出席”。这两个区别的确切性质并不重要,但你应该注意到最终用户认为它们是完全分开的数据。然而,我认为,他们认为他们完全分离的原因是他们从未真正有机会在过去看到他们。这两种类型的记录在编辑记录方面具有几乎完全不同的业务规则,但一般来说

我正在为一个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存储库设计一样,这有一个优点,即“时间卡”的业务规则本身就在一个地方。现在很清楚在哪里可以得到合并列表。但我觉得从两个不同的存储库中获取相同的记录有点奇怪

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

其他的? 我错过了什么?一种设计比另一种设计更有说服力吗

  • 至少据我所知,存储库是一个存放业务规则的地方。它们只是一个用来模仿收藏的门面;在它们下面基本上是纯数据访问(如果这是它们的工作,那么您可能也不会在存储库中持久化任何内容)。因此,出于“业务规则”的原因,不应考虑单独的存储库

  • 如果您的域对象是真正独立的对象,那么您应该拥有独立的存储库。记住存储库是什么:它是一个门面。它模仿一个集合到您的域。有关存储库的非常好的博客文章,请参见此处:

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

    也就是说。。。我不认为你有不同的目标。这里有一些问题与存储库无关,而与域和域的设计有关。这两种“时间卡”实际上是两种不同的东西,还是它们真的是一样的

    你会说,“但我觉得从两个不同的存储库中获取相同的记录有点奇怪。”

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

    如果真的是这样的话,那么这里就有一个公共基类的子类(例如,可以很容易地在DB中建模,并用NHibernate优雅地处理)

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

    我有一个返回广播对象的存储库。我可以将其强制转换为FileBroadcast以处理有关FileBroadcast的特定信息,或者出于相同的原因,我也可以将其强制转换为DeviceBroadcast—如果它属于该类型。广播不能同时为FileBroadcast和DeviceBroadcast类型。它必须是一个或另一个

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

    广播基类有两个子类都使用的通用方法(如GetCommand()方法,该方法返回特定的命令行参数以启动VLC进程)。子类必须重写并实现该方法,因为它是抽象的。这样,FileBroadcast特有的“业务逻辑”就