让我们假设有一个创建用户的操作。如果存在指定的电子邮件或用户名,此操作可能会失败。如果它失败了,它需要知道确切的原因。在我看来,有三种方法可以做到这一点,我想知道是否有明显的赢家。
因此,这里有一个类user:
class User
{
public string Email { get; set; }
public string UserName { get; set; }
}
create操作有三种实现方式:
测试-创建
if (UserExists(user)) act on user exists error;
if (UsernameExists(user)) act on username exists error;
CreateUser(user);
UserExists和UsernameExists向数据库服务器发出请求以进行验证。这些调用在CreateUser中再次重复,以确保正确使用API。如果验证失败,在这两种情况下我都会抛出ArgumentOutOfRangeException。因此,性能会受到影响。
尝试-创建
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;
}
}
此模式只执行一次验证,但我们求助于使用所谓的错误代码,这不被认为是一种好的做法。
Create-Catch
try
{
CreateUser(user);
}
catch(UserExistsException)
{
act on user exists error;
}
catch(UsernameExistsException)
{
act on username exists error;
}
我在这里没有使用错误代码,但我现在必须为每种情况创建一个单独的异常类。这或多或少是关于如何使用异常的,但我想知道创建一个单独的异常而不是枚举条目是否值得。
那么,我们有明确的赢家吗,还是更多的是品味问题?
发布于 2013-04-27 01:19:09
那么,我们有一个明确的赢家吗,或者这更多的是一个品味问题?
第一种选择有一个根本性的缺陷-如果CreateUser
依赖外部资源,那么它永远不会是线程安全或安全的,而其他实现可能会在您的测试之间创建。一般来说,我倾向于避免这种“模式”,因为这一点。
至于其他两种选择--这真的归结于失败是否会发生。如果预计CreateUser
会在某种程度上正常地失败,那么Try*模式是我的首选,因为使用异常基本上变成了使用控制流的异常。
如果失败真的是一个例外情况,那么异常会更容易理解。
发布于 2013-04-27 01:19:04
Test-Create会导致竞争条件,所以这不是一个好主意。它还可能做额外的工作。
如果您希望在正常代码流中出现错误(例如在用户输入的情况下),那么Try-Create是很好的选择。
如果错误确实是异常的(所以您不必担心性能),Create-Catch是很好的选择。
发布于 2013-04-27 01:20:52
这在某种程度上是主观的,但有一些具体的利弊值得指出。
测试-创建方法的一个缺点是竞争条件。如果两个客户端尝试几乎同时创建相同的用户,则它们可能都通过测试,然后尝试创建相同的用户。
在Try-Create和Create-Catch之间,我更喜欢Create-Catch,但这是个人喜好。有人可能会争辩说,Create-Catch使用异常进行流控制,这通常是不受欢迎的。另一方面,Try-Create需要一个有点笨拙的output
参数,这可能更容易被忽略。
所以,我更喜欢Create-Catch,但这里肯定有争论的空间。
https://stackoverflow.com/questions/16241866
复制相似问题