【问题标题】:Should entities implement interfaces?实体应该实现接口吗?
【发布时间】:2010-11-17 11:58:50
【问题描述】:

我个人没有让我的实体实现接口。对于 Task 类,我不会有 ITask 只定义了相同的属性。

我已经看过几次了,所以我想知道这些建议来自哪里,以及从中获得什么好处。

如果您使用的是 ORM,那么“我可以更改我的数据访问权限”的论点是无关紧要的,那么这样做还有什么其他原因?

更新:
关于 INotifyPropertyChanged 在 cmets 中提出了一个很好的观点。不过那不是我的意思——我说的是这样的东西:

public interface ITask
{
    int Id { get; set; }
    string Description { get; set; }
}

public class Task : ITask
{
    public int Id { get; set; }
    public string Description { get; set; }
}

【问题讨论】:

  • 一个字:INotifyPropertyChanged
  • 这肯定需要更多的标签。
  • @bmargulies 如果您愿意,请随时重新标记。我不希望这是特定于语言的,并且不再建议将“最佳实践”作为标签,因此不确定还可以使用什么。
  • 没有人在 Java 中使用过这种意义上的“实体”一词,所以我认为这是特定于 C# 的。

标签: c# class-design


【解决方案1】:

我曾经走过这条路(值对象的接口)。这是一种皇家痛苦,我建议不要这样做。它的常见论点是:

嘲讽: 它们是价值对象。没有什么可嘲笑的。另外,与编写构建器(在 Java 中)或在 C# 中使用命名参数相比,模拟最终会带来很大的痛苦。

只读视图: 我必须承认我仍然更喜欢默认情况下使某些东西不可变,只有在绝对需要时才使其可变。

隐藏功能: 一般来说,范围对我来说已经涵盖了这一点。

【讨论】:

  • 不要忘记 XmlSerializer 完全拒绝序列化接口或反序列化为接口。
  • 如何在不使用界面的情况下制作第二点(只读视图)?
  • 我通常默认情况下使事物不可变。在交给“不安全”的东西或提供只读接口之前进行其他克隆。
  • 是还是不是?
  • 不是。不要为 dtos 创建接口。
【解决方案2】:

这样做的主要好处是它是一种将您的实体公开为“只读”版本的方式(当然,只要您的界面不公开设置器)。

【讨论】:

  • 可以吗?
【解决方案3】:

我们正在进行大量的单元测试,因此经常想模拟我们没有测试的东西。虽然我不喜欢它,但我们最终还是在所有地方都使用了接口,因为它使模拟事物变得更加容易。

理论上大多数模拟框架也可以模拟普通类,但在实践中这给我们带来了问题,因为我们有时会通过反射做一些聪明的事情,并且模拟类的类型与原始类不同。这样做:

var myTask = MyIoCProvider.Get<Task>();
var taskType = typeof(myTask);

无法预测。鉴于:

var myTask = MyIoCProvider.Get<ITask>();
var taskType = typeof(myTask);

为您提供绝对派生自 ITask 的 taskType。

所以接口只是为我们提供了一种使我们的系统更可模拟的方法。

【讨论】:

  • 我明白了。但是,为什么要从 IoC 容器返回实体?我们是在讨论对依赖于其他域对象的完整数据和行为域对象进行单元测试,并且您想模拟这些依赖关系吗?
  • 在我们的例子中,我们区分了像“Task”这样的数据对象和像“TaskAssignmentManager”这样的业务逻辑对象。纯数据对象中没有逻辑,因此不需要模拟、IoC 或接口。如果我们有同时具有逻辑和数据的域对象,我认为我们最终会在它们上使用接口。
【解决方案4】:

如果您考虑使用 DomainEvents 而不是诸如任务之类的数据结构确实需要实现接口

public interface IDomainEvent
{
   Guid EventId { get; }
   Guid TriggeredByEvent { get; }
   DateTime Created { get; }
}

public class OrderCancelledEvent : IDomainEvent
{
   Guid EventId { get; set; }
   Guid TriggeredByEvent { get; set; }
   DateTime Created { get; set; }
   // And now for the specific bit
   int OrderId { get; set; }
}

或者类似地,如果您有一个可能需要接受 IEntity 的标准基类的通用数据访问层,但如果它只是您在帖子中描述的数据结构,我不会为每种类型提供接口。

当您处理实际公开行为的域对象时,您可能希望有一个用于单元测试的接口。

【讨论】:

    【解决方案5】:

    我认为有些程序员只是使用接口,因为他们听说接口很好,所以他们在没有考虑实际利弊的情况下到处使用它们。

    就我个人而言,我从不将接口用于仅表示一条数据(例如 db 行)的实体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-17
      • 2011-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多