有几件事:首先是术语。我不想成为一个术语纳粹 - 只是有一些细微的差异可能会影响你对问题的看法。
DTO 与 POCO
当您谈到 DTO(数据传输对象)时,它听起来更像是 POCO(普通旧 CLR 对象)。
POCO:
- 是一种用于在层之间传递信息的简单数据结构。
- 这通常发生在应用程序中;特别是 .Net 应用程序(托管代码)。
- 它们通常在设计时考虑到SRP(单一职责原则)。
在这种情况下(特定 POCO 的设计)SRP 将意味着“业务”驱动的使用案例(即:在搜索结果中显示“人员”数据的摘要)或通用/以数据为中心的案例(即:提供一个“人”)。
DTO:
直到最近我还盲目地假设 POCO == DTO;当然,很多人(我认为)倾向于那样谈论它们;然后我阅读了 Martin Fowler 对 DTO 的定义,这是不同的。
- 如果在应用程序的层之间使用 POCO,则在应用程序之间使用 DTO。
- 基本原理是,如果您必须通过网络发送数据 - 并且该调用很昂贵 - 那么与其进行多次调用以传递多个对象/数据/无论您将它们全部包装到一个实体中并进行一次调用,不如进行一次调用。该实体就是 DTO。
因此,可以想象,您可能会使用 DTO 将多个 POCO 传递给外部服务。
问题的答案
在设计 POCO(以及层和组件之间的接口)时,您的首要考虑应该是“为什么”?在设计 POCO(和 DTO)时,您会考虑一些不同的观点和动机:
- 责任:谁“拥有” POCO? (即:哪个系统拥有其中的数据)。
- 用例:POCO 是否存在,因为它以一般/通用方式有意义,或者,它是否用于特定/专门目的?
- 性能和其他运行时系统质量:DTO 肯定会受到性能考虑的影响,并且可以想象,在层之间交换信息时,类似的想法也可以应用于 POCO。
因此,您可以考虑以下两种方法...
使用具体 POCO 驱动责任
设计和构建一个 POCO(如在实际的类或结构中)来完成您想要的工作;这将沿着上面讨论的路线(“业务”或“通用/以数据为中心”)。
这就是我目前做事的方式。我经常有一个“胖” POCO,它完整地定义了一个实体(有时包括其他 POCO),以及一个用于列表的“瘦” POCO。我也倾向于使用单独的 POCO 进行保存和更新。
虽然将 POCO 的设计方式标准化是有意义的(例如:它们都由域模型驱动,并且每个实体只有一个 POCO) - 但事实是,您会有不同的动机来自不同的方向;我的建议是屈服于这一点,否则你最终会得到一个不灵活、易于维护或高性能的系统。
使用接口
这是一种更“纯粹”的方法。而不是让您的应用程序围绕使用接口传递具体的 POCO。然后,当您构建实现 POCO 时,它可以实现任意数量的这些接口。例如:
public interface PersonID
{
Guid PersonID { get; }
}
public interface PersonFullName
{
string FirstName { get; }
string Lastname { get; }
string Honorific { get; }
}
public interface PersonDateOfBirth
{
DateTime DateOfBirth { get; }
}
奖励积分
您没有要求这个(至少不是直接要求),但我不会将我的 BL 绑定到 EF - 事实上我根本不会将它绑定到数据访问层。如果你这样做了,任何想要使用你的 BL 的东西也将与 EF 绑定。您可能需要考虑Dependency Inversion。