此应用程序的用户需要跟踪员工的多种时间类型.为了简单起见,我们只考虑两个.我会称他们为“时间卡”和“出席”.这两者之间的差异的确切性质并不重要,但您应该注意到最终用户将它们完全分开.我认为,他们认为他们完全分开数据的原因是,他们从来没有真正有机会在过去看到他们.这两种类型的记录在编辑记录方面几乎完全不同,但一般而言,他们也是在特定时间的员工的记录.两种类型的时间记录具有很多属性,例如总时数,以及收集时间的员工.这两种类型也具有一些完全独特的属性.我们将这些“额外”属性保留在另一种类型的实例中.所以一般结构如下所示:
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
仓库是一个门面;抽象.
那个说…我不认为你有独立的对象.这里有一些与存储库无关的问题,以及域和域的设计.两种类型的“计时卡”实际上是两个不同的东西,还是真的一样?
你说,“但是我觉得有点奇怪,我可以从两个不同的仓库获得同样的记录.”
这告诉我,他们实际上是相同的数据,用不同的方式表达.有办法处理这个问题.
如果真的是这样,那么你在这里就是一个普通基类的子类(例如,可以使用NHibernate来优化DB中的模型,可以在DB中建模).
我会给你一个我正在研究的项目的例子.我有一个叫“广播”的东西.这是一个基础课抽象.无法实例化.我有这个类的两个具体具体类型:DeviceBroadcast和FileBroadcast.一个从设备(如DirectX捕获卡)流式传输音频/视频,一个从文件源(如.mp3)流式传输音频/视频.
我有一个存储库返回一个Broadcast对象.我可以将其转换为FileBroadcast来处理有关FileBroadcast的特定信息,或者因为同样的原因我可以转换为DeviceBroadcast(如果是该类型).广播不能同时是FileBroadcast和DeviceBroadcast类型.它必须是一个或另一个.
在数据库中,我将通用广播参数存储在广播表中,然后将文件特定的属性存储在FileBroadcast表中.对于DeviceBroadcast表也是如此;分离.当我通过存储库进行查询时,我只想要广播.这是我的根聚合对象,因此这是我的存储库.
广播基类具有两个子类使用的常见方法(如GetCommand()方法,它返回一个特定的命令行参数来启动VLC进程).子类必须覆盖并实现该方法,因为它是抽象的.以这种方式,FileBroadcast所特有的“业务逻辑”包含在FileBroadcast类中. DeviceBroadcast唯一的“业务逻辑”包含在DeviceBroadcast类中.任何两者共同的逻辑都包含在超类“Broadcast”中.
你似乎在这里有一个类似的情况,这就是为什么我正在分享我的设计.我认为这可能会为你服务.
最重要的是考虑您的域名和数据.如果您要通过单独的存储库获取重复的数据,那么您需要更多地考虑如何设计域.不要让用户指定您的域名设计.他们从他们的角度知道领域.所有你需要做的是能够以他们理解的方式向他们呈现数据.这并不意味着你必须有一个坏的设计;你可以在幕后有一个很好的设计,因为你的代码是必须使用该域的东西.