7

假设您将系统划分为 Value 对象和 Services 对象(如“Growing Object-Oriented Software, Guided by Tests”中所建议的那样。Misko Hevery 称这些为“newables”和“injectables”。

当你的一个值对象突然需要访问服务来实现它的方法时会发生什么?

假设您有一个不错的简单 Value 对象。它是不可变的,包含一些信息,仅此而已。假设我们像这样使用它:

CreditCard card = new CreditCard("4111-1111-1111-1111", "07/10");
if (card.isValid())
{
  // do stuff
} 
else
{
  // don't do stuff
}

到现在为止还挺好。 isValid()对卡号实现校验位算法并返回真/假。

现在,假设我希望通过根据当前时间验证到期日期来增强系统。您如何建议在不破坏 Value 对象/Service 对象范式的情况下完成此操作?我希望这个类继续是可单元测试的。

  • CreditCard现在有一个依赖,但是由于它的创建方式不能被注入,所以依赖注入已经淘汰了。
  • CreditCard班级不应该呼唤单身人士(我认为全局访问单身人士是不好的做法)
  • 启用该行为CreditCardVerificationService.validateCard()意味着必须重新访问所有现有代码。isValid() 的实现正在泄漏。

我知道可以做一些事情来解决这个问题,但是最干净的方法是什么?

4

3 回答 3

4

我认为验证任何东西都不是 CreditCard 对象的工作。工厂将验证校验位以确保它正在实例化一张合格的卡,而验证服务将验证卡的到期/$ 限制。

于 2010-06-25T12:24:54.223 回答
1

我很想说那CreditCard不是价值对象。

来自C2 维基

值对象的例子有数字、日期、货币和字符串。通常,它们是被广泛使用的小物体。他们的身份基于他们的状态而不是他们的对象身份。这样,您可以拥有同一个概念值对象的多个副本。

值对象不是 BusinessObject/ReferenceObject。BusinessObject/ReferenceObject 是您在世界上找到的东西,而 ValueObject 是对某物的度量或描述。

如果CreditCardNumber可以是一个值对象,CreditCard看起来更像是一个包含一些业务逻辑的业务对象,例如验证。

我通常有值对象、服务和业务对象。我不知道“不断发展的面向对象软件”,但将自己限制在仅使用值对象和服务对我来说似乎很奇怪。

于 2010-06-25T12:52:38.613 回答
0

我会调用CreditCard一个实体而不是值对象,因为它可能是持久的并且具有唯一的身份。

无论如何,实体类使用服务类应该是完全可以的。如果不需要在运行时根据外部配置选择所述服务的实现,那么我只需在客户端方法中实例化并使用所需的服务类。与某些人的想法相反,这并不排除单元测试,因为模拟工具可用于隔离。

如果确实需要在运行时选择服务实现,则可以使用服务定位器。这种模式可以为模拟/伪造提供直接支持,而不需要专门的模拟工具。使用支持注入“新”对象的 DI 框架将是另一种选择。

于 2011-03-28T20:16:57.920 回答