我有一個方法:從C#方法返回不同類型
public ??? AuthManager.Login(Credentials credentials)
下面是一組這種方法的有效輸出值:
- 成功(+帳戶ID)
- 失敗: AccountLockedOut
- 失敗:UsernameNotFound
- 失敗:無效密碼(+失敗的嘗試次數)
根據返回類型,向用戶顯示不同的視圖(是的,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#的discriminated union (DU)。
有沒有更好的方法來建模?我已經有幾個解決方案可行 - 現在我想要一個優雅的解決方案。
會投擲你的項目失敗的例外情況? – Dirk 2013-05-03 15:28:47
Dirks的建議很有意義 - 當一切正常時返回登錄信息 - 當事情出錯並引發任何需要的信息時拋出異常。代碼看起來並不關鍵,但問題是......「登錄失敗是一種特殊情況?」。 ASP.NET成員資格有什麼作用? AD如何? – Charleh 2013-05-03 15:30:51
想到這一點,但我不認爲失敗的登錄是一個例外情況。如果我無法連接到數據庫,或者憑據爲空,則會拋出異常 - 這些異常。我可以將方法重命名爲'TryLogin',以清楚地表明它嘗試登錄,這種失敗嘗試是預期的響應之一。 – 2013-05-03 15:31:34