它的设计是最优选的:测试创建,尝试创建,创建,抓? [英] Which design is most preferable: test-create, try-create, create-catch?

查看:56
本文介绍了它的设计是最优选的:测试创建,尝试创建,创建,抓?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们假设有一个创建用户的操作。如果指定的电子邮件或用户名存在,这个操作可能会失败。如果失败了,则需要确切地知道为什么。 。这样做有,因为我看到它,我想知道是否有一个明显的赢家三种方法



所以,这里的一类用户:

 类用户
{
公共字符串电子邮件{获得;组; }
公共字符串用户名{获得;组; }
}

和有完成创建操作的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆