1

假设我需要在我的系统中注册用户。

商业规则是:

  • 电子邮件应该是唯一的(一种身份);
  • 名称不应为空。

看起来我需要服务。

大概是这样的:

public interface RegistrationService {
  bool Register(String email, String name);
}

在我必须向用户返回失败原因之前,这很好。如何处理?

我可以看到几个选项(但我不喜欢其中任何一个):

  1. 实现一种结果对象:

    public interface RegistrationService { RegistrationResult Register(String email, String name); } 公共接口 RegistrationService { bool Succes(); 错误[] 错误();用户新用户();}

很好,甚至可能对 REST api 有用。但是是不是太麻烦了(特别是考虑到可能应该在工厂检查空白名称)?

  1. 抛出异常

    公共接口 RegistrationService { void Register(String email, String name) throws RegistrationError; }

它看起来更准确一些。但例外是昂贵的。像这样使用它们看起来是个坏主意。

  1. 使用数据库约束。但它看起来比(2)更混乱。
4

2 回答 2

1

让我们从第 3 点开始:数据库约束完成工作。是的,异常/错误消息很混乱,我同意这一点。但问问自己:更混乱的是:向 1 个用户或 2 个具有相同电子邮件地址的用户帐户显示的可怕错误消息可能会破坏您的系统?DB 约束应该是你最后的安全网。您的服务需要检查是否已存在使用此电子邮件的用户帐户。但是,如果在另一个线程中,有人在您检查和创建新用户帐户之间的微秒内使用此电子邮件创建了一个用户帐户,会发生什么?您会对 DB 约束感到满意。是的,您可以找到更好的解决方案,但这需要您有一个单例服务来序列化所有帐户创建,并确保没有两个线程可以同时创建用户帐户。

第 2 点:例外是针对特殊情况。有人想使用已使用的电子邮件创建用户帐户的情况是一种特殊情况。在有人想做脏事的情况下,不要担心代价高昂的操作。

第1点:我不喜欢这个。但那只是我的个人意见。在某些情况下,这种结果对象是有意义的,但我尽量将其保持在最低限度。

于 2018-02-14T09:48:38.130 回答
0

不同的层可以有不同的方式来考虑和发出问题。仅仅因为基础设施引发异常并不意味着所有其他层都应该这样做。

你可以有 :

  • 基础设施:抛出重复键异常,因为客户端不会威胁数据库的完整性
  • 应用程序:捕获异常并返回一个简单的RegistrationResult.Failure值,因为这是预期的失败情况
  • 演示:返回 HTTP 409 冲突
于 2018-02-14T12:16:30.213 回答