我有一个方法:
public ??? AuthManager.Login(Credentials credentials)
这是此方法的一组有效输出值:
- 成功 (+accountId)
- 失败:AccountLockedOut
- 失败:用户名未找到
- 失败:InvalidPassword(+失败尝试计数)
根据返回类型,向用户显示不同的视图(是的,AccountLockedOut 的视图与 InvalidPassword 不同)。
我可以选择:
public class LoginAttemptResult {
public bool Succeeded { get; set; }
public AccountId AccountId { get; set; } // for when success
public LoginAttemptResultEnumType Result { get;set; } // Success, Lockedout, UsernameNotFound, InvalidPassword
public int FailedAttemptCount { get; set; } // only used for InvalidPassword
}
我不喜欢这样,正在寻找更好的解决方案。首先,这导致了一个部分初始化的对象,二是它违反了接口隔离原则,三是它违反了 SRP。
更新:抛出异常也不是一个优雅的解决方案,因为InvalidPassword
我认为它不是异常。失败的数据库连接是一个例外。空参数是一个例外。InvalidPassword
是一个有效的预期响应。
我认为更好的解决方案是创建类的层次结构:
abstract class LoginAttemptResult
sealed class LoginSuccess : LoginAttemptResult { AccountId }
abstract class LoginFailure : LoginAttemptResult
sealed class InvalidPasswordLoginFailure : LoginFailure { FailedAttemptCount }
sealed class AccountLockedoutLoginFailure : LoginFailure
然后方法的调用者Login
必须执行以下操作:
if (result is LoginSuccess) {
..."welcome back mr. account id #" + (result as LoginSuccess).AccountId
}
else if (result is InvalidPasswordLoginFailure ) {
..."you failed " + (result as InvalidPasswordLoginFailure).FailedAttemptCount + " times"
}
我认为这种方法(概念上)没有任何问题(除了它附带的许多类)。
这种方法还有什么问题?
请注意,这种方法本质上是 F# 的可区分联合 (DU)。
有没有更好的方法来建模这个?我已经有几个可行的解决方案 - 现在我想要一个优雅的解决方案。