我有一个方法:
public ??? AuthManager.Login(Credentials credentials)
Run Code Online (Sandbox Code Playgroud)
以下是此方法的一组有效输出值:
根据返回类型,向用户显示不同的视图(是的,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
}
Run Code Online (Sandbox Code Playgroud)
我不喜欢这个并寻找更好的解决方案.首先,这导致部分初始化的对象,其中两个违反了接口隔离原则,三个违反了SRP.
更新:抛出异常也不是一个优雅的解决方案,因为InvalidPassword
我认为这不是一个例外.数据库连接失败是一个例外.空参数是一个例外.InvalidPassword
是一个有效的预期回应.
我认为更好的解决方案是创建类的层次结构:
abstract class LoginAttemptResult
sealed class LoginSuccess : LoginAttemptResult { AccountId }
abstract class LoginFailure : LoginAttemptResult
sealed class InvalidPasswordLoginFailure : LoginFailure { FailedAttemptCount }
sealed class AccountLockedoutLoginFailure : LoginFailure
Run Code Online (Sandbox Code Playgroud)
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"
}
Run Code Online (Sandbox Code Playgroud)
我没有看到任何错误(概念上)这种方法(除了它附带的许多类).
这种方法还有什么问题?
请注意,这种方法本质上是F#的区分联合(DU).
有没有更好的方法来模拟这个?我已经有几个有效的解决方案 - 现在我想要一个优雅的解决方案.
你可以返回一个元组
public Tuple<T1,T2> AuthManager.Login(Credentials credentials){
//do your stuff here
return new Tuple<T1,T2>(valueOfT1,valueOfT2);
}
Run Code Online (Sandbox Code Playgroud)