私は方法を持っています:
public ??? AuthManager.Login(Credentials credentials)
このメソッドの有効な出力値のセットは次のとおりです。
- 成功 (+accountId)
- 失敗: AccountLockedOut
- 失敗: 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
}
私はこれが好きではなく、より良い解決策を探しています。第 1 に、これは部分的に初期化されたオブジェクトになり、2 つはインターフェース分離の原則に違反し、3 つは SRP に違反します。
更新:例外をスローすることもエレガントな解決策ではありません。なぜならInvalidPassword
、それは例外ではないからです。失敗した DB 接続は例外です。null 引数は例外です。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)であることに注意してください。
これをモデル化するより良い方法はありますか?すでに機能するソリューションがいくつかありますが、機能するエレガントなソリューションが必要です。