它的设计是最优选的:测试创建,尝试创建,创建,抓? [英] Which design is most preferable: test-create, try-create, create-catch?
问题描述
让我们假设有一个创建用户的操作。如果指定的电子邮件或用户名存在,这个操作可能会失败。如果失败了,则需要确切地知道为什么。 。这样做有,因为我看到它,我想知道是否有一个明显的赢家三种方法
所以,这里的一类用户:
类用户
{
公共字符串电子邮件{获得;组; }
公共字符串用户名{获得;组; }
}
和有完成创建操作的3种方式:
测试 - 创建
如果(UserExists(用户) )用户的行为是否存在错误;如果用户名(UsernameExists(用户))行为存在错误
;
CREATEUSER(用户);
UserExists和UsernameExists做出请求DB服务器做了验证。这些调用再次重复CREATEUSER确保API的使用是否正确。如果验证失败,我扔ArgumentOutOfRangeException在这两种情况。因此,有一个性能命中。
尝试 - 创建
如果枚举CreateUserResultCode
{
成功,
UserAlreadyExists,
UsernameAlreadyExists
}
(!TryCreate(用户,出resultCode为))
{
开关(resultCode为)
{
案UserAlreadyExists:用户的行为是否存在错误;
案UsernameAlreadyExists:用户名上存在行为偏差;
}
}
这模式确实验证只有一次,但我们诉诸使用这不被认为是一个很好的做法所谓的错误代码。
创建,捕获
试
{
CREATEUSER(用户);
}
赶上(UserExistsException)
{
用户的行为是否存在错误;
}
赶上(UsernameExistsException)
{
上的用户名的行为存在错误;
}
我不会为错误代码,但我现在必须创建一个每一个独立的情况下,异常类。这或多或少异常应该如何被使用的,但我不知道是否创建一个单独的异常,而不是枚举项是值得的。
那么,我们是否有一个明显的赢家或者它更多口味的问题?
那么,我们有一个明确的赢家还是它的?更多口味的问题。
块引用>
第一个选项有一个根本的缺陷 - 它永远不会是线程安全的或安全的,如果
CREATEUSER
依赖于外部资源,和其他可能实现你的测试之间的年创作。在一般情况下,我倾向于避免这一点,因为这个模式
至于其他两个选项 - 它真的归结为失败是的预期的发生。如果
CREATEUSER
预计将失败有点正常的基础上,尝试*模式是我的偏好,因为使用异常本质上成为使用控制流异常。
如果失败将真正成为一个特殊的情况,那么异常会更容易理解。
Let's assume there is an operation that creates a user. This operation may fail if specified email or username exists. If it has failed, it is required to know exactly why. There are three approaches of doing this as I see it and I'm wondering whether there is a clear winner.
So, here's a class user:
class User { public string Email { get; set; } public string UserName { get; set; } }
And there are 3 ways of accomplishing create operation:
Test-Create
if (UserExists(user)) act on user exists error; if (UsernameExists(user)) act on username exists error; CreateUser(user);
UserExists and UsernameExists make request to db server to do a validation. These calls are again repeated in CreateUser to ensure API is used correctly. In case validation has failed, I throw ArgumentOutOfRangeException in both cases. So there is a performance hit.
Try-Create
enum CreateUserResultCode { Success, UserAlreadyExists, UsernameAlreadyExists } if (!TryCreate(user, out resultCode)) { switch(resultCode) { case UserAlreadyExists: act on user exists error; case UsernameAlreadyExists: act on username exists error; } }
This pattern does the validation only once, but we resort to using the so called error codes which isn't considered a good practice.
Create-Catch
try { CreateUser(user); } catch(UserExistsException) { act on user exists error; } catch(UsernameExistsException) { act on username exists error; }
I don't use error codes here, but I now have to create a separate exception class for every case. It's more or less how exceptions are supposed to be used, but I wonder if creating a separate exception instead of enum entry is worthwhile.
So, do we have a clear winner or it's more a matter of taste?
解决方案So, do we have a clear winner or it's more a matter of taste?
The first option has a fundamental flaw - it's never going to be thread safe or safe if
CreateUser
relies on external resources, and other implementations may create in between your tests. In general, I tend to avoid this "pattern" because of this.As for the other two options - it really comes down to whether the failure is expected to happen. If
CreateUser
would be expected to fail on a somewhat normal basis, the Try* pattern is my preference, as using exceptions essentially becomes using exceptions for control flow.If the failure would truly be an exceptional case, then exceptions would be more understandable.
这篇关于它的设计是最优选的:测试创建,尝试创建,创建,抓?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!