我有一个方法:
public ??? AuthManager.Login(Credentials credentials)
>成功(accountId)
>失败:AccountLockedOut
> Failure:UsernameNotFound
>失败: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不是一个例外. DB连接失败是一个例外.空参数是一个例外. InvalidPassword是一个有效的预期响应.
我认为更好的解决方案是创建一个类的层次结构:
abstract class LoginAttemptResult sealed class LoginSuccess : LoginAttemptResult { AccountId } abstract class LoginFailure : LoginAttemptResult sealed class InvalidPasswordLoginFailure : LoginFailure { FailedAttemptCount } sealed class AccountLockedoutLoginFailure : LoginFailure
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#的discriminated union (DU).
解决方法
如果结果类显着不同,您需要一个单独的类,我认为您的解决方案是可行的.但我不知道那个.为每个结果尝试此类:
/// <summary> /// Immutable,created by the server /// </summary> class LoginResult { /// <summary> /// Null in the case of failure /// </summary> public int? Id { get; private set; } /// <summary> /// Null in the case of success /// </summary> public string FailReason { get; private set; } /// <summary> /// Always >= 1 /// </summary> public int AttemptNumber { get; private set; } public LoginResult(int id,int attemptNumber) { Id = id; AttemptNumber = attemptNumber; } public LoginResult(string reason,int attemptNumber) { FailReason = reason; AttemptNumber = attemptNumber; } }
我可以想象,您的身份验证逻辑可能非常复杂,Id,FailReason和AttemptNumber不仅仅是您需要的属性.在这种情况下,您需要向我们介绍更具体的例子,我们将尝试构建适合您的逻辑的抽象,如果必要的话.在这种特殊情况下 – 抽象没有意义.