1

私は OOP を初めて使用するので、これが正しい処理方法であるかどうかを理解するために助けが必要です。私は 3 層 Web プロジェクト (+ DTO) を持っており、ビジネス オブジェクトからプレゼンテーション層に「エラー」を返す最良の方法を理解しようとしています。特に今、私はこのユーザーの作成に直面しています。ウェブサイトの登録時にデータベースにユーザーを作成したいとしましょう。ユーザー名または電子メールが既に取得されているかどうかを実際のユーザーに伝える必要があります (これは単なる例です)。

たとえば、ASP.NET Membership.CreateUser() メソッドは、MembershipCreateStatus オブジェクト byRef を渡すため、このメソッドを使用して Enum (別の名前空間に存在します...) を返し、試行のステータスを渡します。これは、DuplicateEmail の可能性があります。 DuplicateUserName など。

例外に基づいて別の方法を実装しましたが、それについての意見をお願いします。ユーザーを作成する BLL マネージャー クラスで、ネストされた Excpetion クラスと、エラー タイプのネストされた Enum を次のように作成しました。

Public Class UserManager
    Public Enum ErrorType
        DatabaseError = 1
        UserExists = 2
        EmailExists = 3
    End Enum

    Public Class ManagerException
        Inherits Exception

        Public Property ErrorType As ErrorType
        Public Property SuggestedUserName As String
        Public Property SuggestedEmail As String

        Public Sub New()
            MyBase.New()
        End Sub

        Public Sub New(message As String)
            MyBase.New(message)
        End Sub

        Public Sub New(message As String, inner As Exception)
            MyBase.New(message, inner)
        End Sub
    End Class


    Public Function CreateUserLogin(user As EvaVwUserLogin) As Guid
        If user Is Nothing Then
            Throw New ApplicationException("No user suppied")
        End If

        If String.IsNullOrWhiteSpace(user.Password) OrElse String.IsNullOrWhiteSpace(user.UserName) Then
            Throw New ApplicationException("Password or username missing")
        End If

        If CheckDuplicateUserName() Then
            Dim ex As New ManagerException("Username exists")

            ex.ErrorType = ErrorType.UserExists
            ex.SuggestedUserName = "this username is free"

            Throw ex
        End If
    End Function
End Class

次に、UI レイヤー (aspx コード ビハインド) でマネージャーを呼び出し、次のように例外を確認します。

        Dim userManager As New UserManager

        Try
            userManager.CreateUserLogin("test", "test")
        Catch ex As UserManager.ManagerException
            If ex.ErrorType = userManager.ErrorType.UserExists Then
                Dim suggestedUsername = ex.SuggestedUserName

                ' Display error message and suggested user name
            End If
        End Try

例外と列挙型の両方がこのマネージャーに非常に固有であるため、このルートをたどると、各マネージャーに関連する列挙型を持つネストされた ManagerException があることを考えると、これは正しいアプローチですか?

いつもご意見ありがとうございます。


Brian と Cyborg によって親切に提案された「カスタム コード」シナリオをフォローアップします (Brian の方がより完全であるという理由だけで彼の回答にマークを付けました。他のユーザーが MS のアドバイスに興味を持っている可能性があります)。良い考えでしょうか?これらの列挙型はこのマネージャー クラスに厳密に関連付けられるため (そして、BLL の各マナガー クラスには独自のクラスがあります)、ステータス コードが渡されたときにそれらを引き続き使用できると思いますか?

編集:私はこのようにリファクタリングしました...大丈夫だと思いますか?

Public Class UserManager
    Public Enum ErrorType
        DatabaseError = 1
        UserExists = 2
        EmailExists = 3
    End Enum

    Public Class ErrorData
        Public Property ErrorType As ErrorType
        Public Property SuggestedUserName As String
        Public Property SuggestedEmail As String
    End Class

    Public Function CreateUserLogin(username As String, password As String, ByRef errorData As ErrorData) As Guid
        Dim user As New EvaVwUserLogin

        user.UserName = username
        user.Password = password

        Return CreateUserLogin(user, errorData)
    End Function

    Public Function CreateUserLogin(user As EvaVwUserLogin, ByRef errorData As ErrorData) As Guid
        If user Is Nothing Then
            Throw New ApplicationException("No user object")
        End If

        If String.IsNullOrWhiteSpace(user.Password) OrElse String.IsNullOrWhiteSpace(user.UserName) Then
            Throw New ApplicationException("Missing password or username")
        End If

        Dim hashedPassword As String

        hashedPassword = Crypto.HashPassword(user.Password)

        If UserExists(user) Then
            errorData.ErrorType = ErrorType.UserExists
            errorData.SuggestedUserName = "this username is free"
            Return Nothing
        End If
        .....
    End Function
End Class

そして、プレゼンテーション層では:

        Dim userManager As New UserManager
        Dim managerError As New UserManager.ErrorData
        Dim userId As Guid

        userId = userManager.CreateUserLogin("test", "test", managerError)

        If userId = Nothing Then
            If managerError.ErrorType = userManager.ErrorType.UserExists Then
                Dim suggestedUserName = managerError.SuggestedUserName

                ' Do something with suggested user name
            End If
        End If
4

2 に答える 2

2

そのためには、Membership API の機能に従います。ビューが応答を確認するために使用できる、ビジネス コンポーネントから列挙型を返します。したがって、ASP.NET ページに言及したような値を持つ列挙型を返し、そこで型を確認します。あなたはあなたがしていることをすることができますが、私が見たところ、それは必要ではないと思います。さらに、例外のスローはコストがかかります。

列挙型の意味を明確にするために、例外を介してではなく、ビジネス コンポーネントの呼び出し元からそれを返します。

于 2013-01-14T20:45:58.930 に答える
1

(この回答は、例外ではなくリターン コードを使用するという @BrianMains の提案をサポートするためのものです。関連するドキュメントが大きすぎてコメントに収まりませんでした。)

例外に関するMSDNのドキュメントから:

例外をスローまたは処理すると、大量のシステム リソースと実行時間が使用されます。予測可能なイベントやフロー制御を処理するためではなく、本当に異常な状況を処理するためだけに例外をスローします。たとえば、有効なパラメーターを使用してメソッドを呼び出すことが期待されるため、メソッドの引数が無効な場合、アプリケーションは合理的に例外をスローできます。無効なメソッド引数は、何か異常が発生したことを意味します。逆に、ユーザーが無効なデータを入力する場合があるため、ユーザー入力が無効な場合は例外をスローしないでください。このような場合は、再試行メカニズムを提供して、ユーザーが有効な入力を入力できるようにします。

異常な状況に対してのみ例外をスローし、特定の例外に適用されるハンドラーではなく、アプリケーションの大部分に適用される汎用の例外ハンドラーで例外をキャッチします。このアプローチの理論的根拠は、ほとんどのエラーは、エラーに近い検証およびエラー処理コードによって処理できるということです。例外をスローまたはキャッチする必要はありません。汎用例外ハンドラーは、アプリケーション内のどこかでスローされた本当に予期しない例外をキャッチします。

さらに、戻りコードが十分な場合は例外をスローしないでください。戻りコードを例外に変換しないでください。定期的に例外をキャッチせず、無視してから処理を続行します。

http://msdn.microsoft.com/en-us/library/system.exception.aspx

(私のハイライト)

于 2013-01-14T20:56:08.870 に答える