哪个devise是最可取的:test-create,try-create,create-catch?
我们假设有一个操作可以创build一个用户。 如果指定的电子邮件地址或用户名称存在 如果失败了,就需要知道原因。 我看到这样做有三种方法,我想知道是否有明确的赢家。
所以,这里是一个类的用户:
class User { public string Email { get; set; } public string UserName { get; set; } }
创build操作有三种方式:
testing创build
if (UserExists(user)) act on user exists error; if (UsernameExists(user)) act on username exists error; CreateUser(user);
UserExists和UsernameExists请求数据库服务器进行validation。 这些调用在CreateUser中再次重复,以确保API正确使用。 在validation失败的情况下,我在这两种情况下抛出ArgumentOutOfRangeException。 所以有一个性能问题。
尝试-创build
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; } }
这种模式只进行一次validation,但我们诉诸使用所谓的错误代码,这不被认为是一种好的做法。
创build,捕捉
try { CreateUser(user); } catch(UserExistsException) { act on user exists error; } catch(UsernameExistsException) { act on username exists error; }
我在这里不使用错误代码,但是现在我必须为每个情况创build一个单独的exception类。 这或多或less是应该如何使用exception,但我不知道创build一个单独的exception,而不是枚举input是值得的。
那么,我们有一个明确的赢家还是更多的味道?
那么,我们有一个明确的赢家还是更多的味道?
第一个选项有一个根本的缺陷 – 如果CreateUser
依赖于外部资源,那么它永远不会是线程安全的或安全的,其他实现可能会在您的testing之间创build。 总的来说,我倾向于避免这种“模式”。
至于其他两种select – 这是否真的会发生失败。 如果CreateUser
预期会在某种程度上正常的基础上失败,那么Try *模式是我的首选,因为使用exception本质上将使用控制stream的exception。
如果失败确实是一个例外情况,那么例外情况就会更容易理解。
testing创build可能会导致竞争条件,所以这不是一个好主意。 它也可能做额外的工作。
如果您希望错误成为正常代码stream的一部分(例如用户input的情况),则Try-Create是很好的。
如果错误是非常特殊的,那么Create-Catch是很好的(所以你不担心性能)。
这是有点主观的,但有一些具体的利弊值得指出。
testing创build方法的一个缺点是竞争条件。 如果两个客户端大致同时尝试创build相同的用户,则可能两个客户都通过testing,然后尝试创build相同的用户。
在Try-Create和Create-Catch之间,我更喜欢Create-Catch,但那是个人的品味。 有人可能会争辩说,Create-Catch使用stream控制的exception,这通常是不被接受的。 另一方面,Try-Create需要一个稍微笨拙的output
参数,这个参数可能更容易被忽略。
所以,我更喜欢Create-Catch,但是这里肯定有争议的空间。
您指定UserExists
和UsernameExists
都进行数据库调用。 我假设CreateUser
也会进行数据库调用。
为什么不让数据库处理你的线程问题? 进一步假设在你的表上设置了适当的约束条件,你可以让它在存储的proc调用中出错。
因此,我会投我Create-Catch的投票。